Add banlist to file functions and configuration params.
[umurmur.git] / src / ban.c
1 /* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2012, 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         memcpy(&ban->address, &client->remote_tcp.sin_addr, sizeof(in_addr_t));
78         ban->mask = 128;
79         ban->reason = strdup(reason);
80         ban->name = strdup(client->username);
81         ban->time = time(NULL);
82         ban->duration = ban_duration;
83         Timer_init(&ban->startTime);
84         list_add_tail(&ban->node, &banlist);
85         bancount++;
86         banlist_changed = true;
87         if(getBoolConf(SYNC_BANFILE))
88                 Ban_saveBanFile();
89         
90         SSLi_hash2hex(ban->hash, hexhash);
91         Log_info_client(client, "User kickbanned. Reason: '%s' Hash: %s IP: %s Banned for: %d seconds",
92                         ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
93                         ban->duration);
94 }
95
96
97 void Ban_pruneBanned()
98 {
99         struct dlist *itr;
100         ban_t *ban;
101         char hexhash[41];
102         uint64_t bantime_long;
103                 
104         list_iterate(itr, &banlist) {
105                 ban = list_get_entry(itr, ban_t, node);
106                 bantime_long = ban->duration * 1000000LL;
107 #ifdef DEBUG
108                 SSLi_hash2hex(ban->hash, hexhash);
109                 Log_debug("BL: User %s Reason: '%s' Hash: %s IP: %s Time left: %d",
110                           ban->name, ban->reason, hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
111                           bantime_long / 1000000LL - Timer_elapsed(&ban->startTime) / 1000000LL);
112 #endif
113                 /* Duration of 0 = forever */
114                 if (ban->duration != 0 && Timer_isElapsed(&ban->startTime, bantime_long)) {
115                         free(ban->name);
116                         free(ban->reason);
117                         list_del(&ban->node);
118                         free(ban);
119                         bancount--;
120                         banlist_changed = true;
121                         if(getBoolConf(SYNC_BANFILE))
122                                 Ban_saveBanFile();
123                 }
124         }
125 }
126
127 bool_t Ban_isBanned(client_t *client)
128 {
129         struct dlist *itr;
130         ban_t *ban;
131         list_iterate(itr, &banlist) {
132                 ban = list_get_entry(itr, ban_t, node);
133                 if (memcmp(ban->hash, client->hash, 20) == 0) 
134                         return true;
135         }
136         return false;
137         
138 }
139
140 bool_t Ban_isBannedAddr(in_addr_t *addr)
141 {
142         struct dlist *itr;
143         ban_t *ban;
144         int mask;
145         in_addr_t tempaddr1, tempaddr2;
146         
147         list_iterate(itr, &banlist) {
148                 ban = list_get_entry(itr, ban_t, node);
149                 mask = ban->mask - 96;
150                 if (mask < 32) { /* XXX - only ipv4 support */
151                         memcpy(&tempaddr1, addr, sizeof(in_addr_t));
152                         memcpy(&tempaddr2, &ban->address, sizeof(in_addr_t));
153                         tempaddr1 &= (2 ^ mask) - 1;
154                         tempaddr2 &= (2 ^ mask) - 1;
155                 }
156                 if (memcmp(&tempaddr1, &tempaddr2, sizeof(in_addr_t)) == 0) 
157                         return true;
158         }
159         return false;
160 }
161
162 int Ban_getBanCount(void)
163 {
164         return bancount;
165 }
166
167 message_t *Ban_getBanList(void)
168 {
169         int i = 0;
170         struct dlist *itr;
171         ban_t *ban;
172         message_t *msg;
173         struct tm timespec;
174         char timestr[32];
175         char hexhash[41];
176         uint8_t address[16];
177         
178         msg = Msg_banList_create(bancount);
179         list_iterate(itr, &banlist) {
180                 ban = list_get_entry(itr, ban_t, node);
181                 gmtime_r(&ban->time, &timespec);
182                 strftime(timestr, 32, "%Y-%m-%dT%H:%M:%S", &timespec);
183                 SSLi_hash2hex(ban->hash, hexhash);
184                 /* ipv4 representation as ipv6 address. */
185                 memset(address, 0, 16);
186                 memcpy(&address[12], &ban->address, 4);
187                 memset(&address[10], 0xff, 2); /* IPv4 */
188                 Msg_banList_addEntry(msg, i++, address, ban->mask, ban->name,
189                                      hexhash, ban->reason, timestr, ban->duration);
190         }
191         return msg;
192 }
193
194 void Ban_clearBanList(void)
195 {
196         ban_t *ban;
197         struct dlist *itr, *save;
198         list_iterate_safe(itr, save, &banlist) {
199                 ban = list_get_entry(itr, ban_t, node);
200                 free(ban->name);
201                 free(ban->reason);
202                 list_del(&ban->node);
203                 free(ban);
204                 bancount--;
205         }
206 }
207
208 void Ban_putBanList(message_t *msg, int n_bans)
209 {
210         int i = 0;
211         struct tm timespec;
212         ban_t *ban;
213         char *hexhash, *name, *reason, *start;
214         uint32_t duration, mask;
215         uint8_t *address;
216         
217         for (i = 0; i < n_bans; i++) {
218                 Msg_banList_getEntry(msg, i, &address, &mask, &name, &hexhash, &reason, &start, &duration);
219                 ban = malloc(sizeof(ban_t));
220                 if (ban == NULL)
221                         Log_fatal("Out of memory");
222                 memset(ban, 0, sizeof(ban_t));
223                 SSLi_hex2hash(hexhash, ban->hash);
224                 memcpy(&ban->address, &address[12], 4);
225                 ban->mask = mask;
226                 ban->reason = strdup(reason);
227                 ban->name = strdup(name);
228                 strptime(start, "%Y-%m-%dT%H:%M:%S", &timespec);
229                 ban->time = mktime(&timespec);
230                 Timer_init(&ban->startTime);
231                 ban->duration = duration;
232                 list_add_tail(&ban->node, &banlist);
233                 bancount++;
234         }
235         banlist_changed = true;
236         if(getBoolConf(SYNC_BANFILE))
237                 Ban_saveBanFile();
238 }
239
240 static void Ban_saveBanFile(void)
241 {
242         struct dlist *itr;
243         ban_t *ban;
244         char hexhash[41];
245         FILE *file;
246
247         if (!banlist_changed)
248                 return;
249         file = fopen(getStrConf(BANFILE), "w");
250         if (file == NULL) {
251                 Log_warn("Could not save banlist to file %s: %s", getStrConf(BANFILE), strerror(errno));
252                 return;
253         }
254         list_iterate(itr, &banlist) {
255                 ban = list_get_entry(itr, ban_t, node);
256                 SSLi_hash2hex(ban->hash, hexhash);
257                 fprintf(file, "%s,%s,%d,%d,%d,%s,%s\n", hexhash, inet_ntoa(*((struct in_addr *)&ban->address)),
258                         ban->mask, ban->time, ban->duration, ban->name, ban->reason);
259         }
260         fclose(file);
261 }
262
263 static void Ban_readBanFile(void)
264 {
265         struct dlist *itr;
266         ban_t *ban;
267         char line[512], *hexhash, *address, *name, *reason;
268         uint32_t mask, duration;
269         time_t time;
270         char *p;
271         FILE *file;
272
273         file = fopen(getStrConf(BANFILE), "r");
274         if (file == NULL) {
275                 Log_warn("Could not read banlist file %s: %s", getStrConf(BANFILE), strerror(errno));
276                 return;
277         }
278         while (fgets(line, 512, file) != NULL) {
279                 p = strtok(line, ",");
280                 hexhash = p;
281                 p = strtok(NULL, ",");
282                 if (p == NULL) break;
283                 address = p;
284                 p = strtok(NULL, ",");
285                 if (p == NULL) break;
286                 mask = strtoul(p, NULL, 0);
287                 p = strtok(NULL, ",");
288                 if (p == NULL) break;
289                 time = strtoul(p, NULL, 0);
290                 p = strtok(NULL, ",");
291                 if (p == NULL) break;
292                 duration = strtoul(p, NULL, 0);
293                 p = strtok(NULL, ",");
294                 if (p == NULL) break;
295                 name = p;
296                 p = strtok(NULL, "\n");
297                 if (p == NULL) break;
298                 reason = p;
299                 
300                 ban = malloc(sizeof(ban_t));
301                 if (ban == NULL)
302                         Log_fatal("Out of memory");
303                 memset(ban, 0, sizeof(ban_t));
304                 SSLi_hex2hash(hexhash, ban->hash);
305                 inet_aton(address, (struct in_addr *)&ban->address);
306                 ban->name = strdup(name);
307                 ban->reason = strdup(reason);
308                 ban->time = time;
309                 ban->duration = duration;
310                 ban->mask = mask;
311                 Timer_init(&ban->startTime);
312                 list_add_tail(&ban->node, &banlist);
313                 bancount++;
314                 Log_debug("Banfile: H = '%s' A = '%s' M = %d U = '%s' R = '%s'", hexhash, address, ban->mask, ban->name, ban->reason);
315         }
316         fclose(file);
317 }