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