e5294ba3f45f2d2229a7d3a45decb5a1377e71cb
[umurmur.git] / src / ban.c
1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
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.
18
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.
30 */
31
32 #include <stdlib.h>
33 #include <time.h>
34 #include "log.h"
35 #include "list.h"
36 #include "ban.h"
37 #include "conf.h"
38 #include "ssl.h"
39
40 static void Ban_saveBanFile(void);
41 static void Ban_readBanFile(void);
42
43
44 declare_list(banlist);
45 static int bancount; /* = 0 */
46 static int ban_duration;
47 static bool_t banlist_changed;
48
49 void Ban_init(void)
50 {
51         ban_duration = getIntConf(BAN_LENGTH);
52         /* Read ban file here */
53         if (getStrConf(BANFILE) != NULL)
54                 Ban_readBanFile();
55 }
56
57 void Ban_deinit(void)
58 {
59         /* Save banlist */
60         if (getStrConf(BANFILE) != NULL)
61                 Ban_saveBanFile();
62
63         Ban_clearBanList();
64 }
65
66 void Ban_UserBan(client_t *client, char *reason)
67 {
68         ban_t *ban;
69         char hexhash[41];
70
71         ban = malloc(sizeof(ban_t));
72         if (ban == NULL)
73                 Log_fatal("Out of memory");
74         memset(ban, 0, sizeof(ban_t));
75
76         memcpy(ban->hash, client->hash, 20);
77   if (client->remote_tcp.ss_family == AF_INET) {
78     memcpy(&ban->address, &(((struct sockaddr_in*)&client->remote_tcp)->sin_addr), sizeof(in_addr_t));
79     ban->mask = sizeof(in_addr_t);
80   } else {
81     memcpy(&ban->address, &(((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr), 4 * sizeof(in_addr_t));
82     ban->mask = 4 * sizeof(in_addr_t);
83   }
84         ban->reason = strdup(reason);
85         ban->name = strdup(client->username);
86         ban->time = time(NULL);
87         ban->duration = ban_duration;
88         Timer_init(&ban->startTime);
89         list_add_tail(&ban->node, &banlist);
90         bancount++;
91         banlist_changed = true;
92         if(getBoolConf(SYNC_BANFILE))
93                 Ban_saveBanFile();
94
95         SSLi_hash2hex(ban->hash, hexhash);
96
97   char addressPresentation[INET6_ADDRSTRLEN];
98
99   if(client->remote_tcp.ss_family == AF_INET)
100     inet_ntop(AF_INET, &((struct sockaddr_in*)&client->remote_tcp)->sin_addr, addressPresentation, INET6_ADDRSTRLEN);
101   else
102     inet_ntop(AF_INET6, &((struct sockaddr_in6*)&client->remote_tcp)->sin6_addr, addressPresentation, INET6_ADDRSTRLEN);
103
104         Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
105                         ban->reason, hexhash, addressPresentation, ban->duration);
106 }
107
108
109 void Ban_pruneBanned()
110 {
111         struct dlist *itr;
112         ban_t *ban;
113         char hexhash[41];
114         uint64_t bantime_long;
115
116         list_iterate(itr, &banlist) {
117                 ban = list_get_entry(itr, ban_t, node);
118                 bantime_long = ban->duration * 1000000LL;
119 #ifdef DEBUG
120                 SSLi_hash2hex(ban->hash, hexhash);
121                 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
122                           ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
123                           bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
124 #endif
125                 /* Duration of 0 = forever */
126                 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
127                         free(ban->name);
128                         free(ban->reason);
129                         list_del(&ban->node);
130                         free(ban);
131                         bancount--;
132                         banlist_changed = true;
133                         if(getBoolConf(SYNC_BANFILE))
134                                 Ban_saveBanFile();
135                 }
136         }
137 }
138
139 bool_t Ban_isBanned(client_t *client)
140 {
141         struct dlist *itr;
142         ban_t *ban;
143         list_iterate(itr, &banlist) {
144                 ban = list_get_entry(itr, ban_t, node);
145                 if (memcmp(ban->hash, client->hash, 20) == 0)
146                         return true;
147         }
148         return false;
149
150 }
151
152 bool_t Ban_isBannedAddr(in_addr_t *addr)
153 {
154         struct dlist *itr;
155         ban_t *ban;
156         int mask;
157         in_addr_t tempaddr1, tempaddr2;
158
159         list_iterate(itr, &banlist) {
160                 ban = list_get_entry(itr, ban_t, node);
161                 mask = ban->mask - 96;
162                 if (mask < 32) { /* XXX - only ipv4 support */
163                         memcpy(&tempaddr1, addr, sizeof(in_addr_t));
164                         memcpy(&tempaddr2, &ban->address, sizeof(in_addr_t));
165                         tempaddr1 &= (2 ^ mask) - 1;
166                         tempaddr2 &= (2 ^ mask) - 1;
167                 }
168                 if (memcmp(&tempaddr1, &tempaddr2, sizeof(in_addr_t)) == 0)
169                         return true;
170         }
171         return false;
172 }
173
174 int Ban_getBanCount(void)
175 {
176         return bancount;
177 }
178
179 message_t *Ban_getBanList(void)
180 {
181         int i = 0;
182         struct dlist *itr;
183         ban_t *ban;
184         message_t *msg;
185         struct tm timespec;
186         char timestr[32];
187         char hexhash[41];
188         uint8_t address[16];
189
190         msg = Msg_banList_create(bancount);
191         list_iterate(itr, &banlist) {
192                 ban = list_get_entry(itr, ban_t, node);
193                 gmtime_r(&ban->time, &timespec);
194                 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", &timespec);
195                 SSLi_hash2hex(ban->hash, hexhash);
196                 /* ipv4 representation as ipv6 address. */
197                 memset(address, 0, 16);
198                 memcpy(&address[12], &ban->address, 4);
199                 memset(&address[10], 0xff, 2); /* IPv4 */
200                 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name,
201                                      hexhash, ban->reason, timestr, ban->duration);
202         }
203         return msg;
204 }
205
206 void Ban_clearBanList(void)
207 {
208         ban_t *ban;
209         struct dlist *itr, *save;
210         list_iterate_safe(itr, save, &banlist) {
211                 ban = list_get_entry(itr, ban_t, node);
212                 free(ban->name);
213                 free(ban->reason);
214                 list_del(&ban->node);
215                 free(ban);
216                 bancount--;
217         }
218 }
219
220 void Ban_putBanList(message_t *msg, int n_bans)
221 {
222         int i = 0;
223         struct tm timespec;
224         ban_t *ban;
225         char *hexhash, *name, *reason, *start;
226         uint32_t duration, mask;
227         uint8_t *address;
228
229         for (i = 0; i < n_bans; i++) {
230                 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
231                 ban = malloc(sizeof(ban_t));
232                 if (ban == NULL)
233                         Log_fatal("Out of memory");
234                 memset(ban, 0, sizeof(ban_t));
235                 SSLi_hex2hash(hexhash, ban->hash);
236                 memcpy(&ban->address, &address[12], 4);
237                 ban->mask = mask;
238                 ban->reason = strdup(reason);
239                 ban->name = strdup(name);
240                 strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
241                 ban->time = mktime(&timespec);
242                 ban->startTime = ban->time * 1000000LL;
243                 ban->duration = duration;
244                 list_add_tail(&ban->node, &banlist);
245                 bancount++;
246         }
247         banlist_changed = true;
248         if(getBoolConf(SYNC_BANFILE))
249                 Ban_saveBanFile();
250 }
251
252 static void Ban_saveBanFile(void)
253 {
254         struct dlist *itr;
255         ban_t *ban;
256         char hexhash[41];
257         FILE *file;
258
259         if (!banlist_changed)
260                 return;
261         file = fopen(getStrConf(BANFILE), "w");
262         if (file == NULL) {
263                 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
264                 return;
265         }
266         list_iterate(itr, &banlist) {
267                 ban = list_get_entry(itr, ban_t, node);
268                 SSLi_hash2hex(ban->hash, hexhash);
269                 fprintf(file, "%s,%s,%d,%ld,%d,%s,%s\n", hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
270                         ban->mask, (long int)ban->time, ban->duration, ban->name, ban->reason);
271         }
272         fclose(file);
273         banlist_changed = false;
274         Log_info("Banlist file '%s': %d entries written", getStrConf(BANFILE), bancount);
275 }
276
277 static void Ban_readBanFile(void)
278 {
279         struct dlist *itr;
280         ban_t *ban;
281         char line[1024], *hexhash, *address, *name, *reason;
282         uint32_t mask, duration;
283         time_t time;
284         char *p;
285         FILE *file;
286
287         file = fopen(getStrConf(BANFILE), "r");
288         if (file == NULL) {
289                 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
290                 return;
291         }
292         while (fgets(line, 1024, file) != NULL) {
293                 p = strtok(line, ",");
294                 hexhash = p;
295                 p = strtok(NULL, ",");
296                 if (p == NULL) break;
297                 address = p;
298                 p = strtok(NULL, ",");
299                 if (p == NULL) break;
300                 mask = strtoul(p, NULL, 0);
301                 p = strtok(NULL, ",");
302                 if (p == NULL) break;
303                 time = strtoul(p, NULL, 0);
304                 p = strtok(NULL, ",");
305                 if (p == NULL) break;
306                 duration = strtoul(p, NULL, 0);
307                 p = strtok(NULL, ",");
308                 if (p == NULL) break;
309                 name = p;
310                 p = strtok(NULL, "\n");
311                 if (p == NULL) break;
312                 reason = p;
313
314                 ban = malloc(sizeof(ban_t));
315                 if (ban == NULL)
316                         Log_fatal("Out of memory");
317                 memset(ban, 0, sizeof(ban_t));
318                 SSLi_hex2hash(hexhash, ban->hash);
319                 inet_aton(address, (struct in_addr *)&ban->address);
320                 ban->name = strdup(name);
321                 ban->reason = strdup(reason);
322                 if (ban->name == NULL || ban->reason == NULL)
323                         Log_fatal("Out of memory");
324                 ban->time = time;
325                 ban->duration = duration;
326                 ban->mask = mask;
327                 ban->startTime = ban->time * 1000000LL;
328                 list_add_tail(&ban->node, &banlist);
329                 bancount++;
330                 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
331         }
332         fclose(file);
333         Log_info("Banlist file '%s': %d entries read", getStrConf(BANFILE), bancount);
334 }