Author: Isomer
[ircu2.10.12-pk.git] / ircd / IPcheck.c
1 /*
2  * IRC - Internet Relay Chat, ircd/IPcheck.c
3  * Copyright (C) 1998 Carlo Wood ( Run @ undernet.org )
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  * $Id$
20  *
21  */
22 #include "IPcheck.h"
23 #include "client.h"
24 #include "ircd.h"
25 #include "numnicks.h"
26 #include "ircd_alloc.h"
27 #include "msg.h"
28 #include "s_bsd.h"
29 #include "s_debug.h"
30 #include "s_user.h"
31 #include "send.h"
32
33 #include <assert.h>
34 #include <arpa/inet.h>
35 #include <stdio.h>
36 #include <string.h>
37
38 #if 0
39 #warning Nick collisions are horribly broken in
40 #warning this version, and its known to core on
41 #warning a whim.  If your even concidering
42 #warning running this on something resembling a
43 #warning production network, dont bother, its
44 #warning not worth your time.  To those of you
45 #warning who grabbed the latest CVS version to
46 #warning bug test it, thanks, but I recommend
47 #warning you stick to previous versions for the
48 #warning time being.
49 #error --- Broken code ---
50 #endif
51
52 struct IPTargetEntry {
53   int           count;
54   unsigned char targets[MAXTARGETS];
55 };
56
57 struct IPRegistryEntry {
58   struct IPRegistryEntry *next;
59   struct IPTargetEntry   *target;
60   unsigned int             addr;
61   time_t                  last_connect;
62   unsigned char            connected;
63   unsigned char            attempts;
64 };
65
66
67 /*
68  * Hash table for IPv4 address registry
69  *
70  * Hash table size must be a power of 2
71  * Use 64K hash table to conserve memory
72  */
73 /*----------------------------------------------------------------------------
74  * Compile-time Configuration
75  *--------------------------------------------------------------------------*/
76 #define IP_REGISTRY_TABLE_SIZE 0x10000
77 #define MASK_16                0xffff
78
79 /* We allow 6 connections in 60 seconds */
80 #define IPCHECK_CLONE_LIMIT 6
81 #define IPCHECK_CLONE_PERIOD 60
82 #define IPCHECK_CLONE_DELAY  600
83
84
85 /*----------------------------------------------------------------------------
86  * Handy Macros
87  *--------------------------------------------------------------------------*/
88 #define NOW (CurrentTime)
89 #define CONNECTED_SINCE(x) (NOW - (x->last_connect))
90
91
92 /*----------------------------------------------------------------------------
93  * Global Data (ugly!)
94  *--------------------------------------------------------------------------*/
95 static struct IPRegistryEntry *hashTable[IP_REGISTRY_TABLE_SIZE];
96 static struct IPRegistryEntry *freeList = 0;
97
98
99 /*----------------------------------------------------------------------------
100  * ip_registry_hash:  Create a hash key for an IP registry entry and return
101  *                    the value.  (Is unsigned int really a good type to give
102  *                    to the IP argument?  Ugly.  This should probably be a
103  *                    struct in_addr.  This is asking for trouble.  --ZS)
104  *--------------------------------------------------------------------------*/
105 static unsigned int ip_registry_hash(unsigned int ip)
106 {
107   return ((ip >> 16) ^ ip) & (IP_REGISTRY_TABLE_SIZE - 1);
108 }
109
110
111 /*----------------------------------------------------------------------------
112  * ip_registry_find:  Find a given IP registry entry and return it.
113  *--------------------------------------------------------------------------*/
114 static struct IPRegistryEntry *ip_registry_find(unsigned int ip) 
115 {
116   struct IPRegistryEntry *entry = 0;
117
118   for (entry = hashTable[ip_registry_hash(ip)]; entry; entry = entry->next) {
119     if (entry->addr == ip)
120       return entry;
121   }
122
123   return NULL;
124 }
125
126
127 /*----------------------------------------------------------------------------
128  * ip_registry_add:  Add an entry to the IP registry
129  *--------------------------------------------------------------------------*/
130 static void ip_registry_add(struct IPRegistryEntry *entry) 
131 {
132   unsigned int bucket = ip_registry_hash(entry->addr);
133
134   entry->next = hashTable[bucket];
135   hashTable[bucket] = entry;
136 }
137   
138
139 /*----------------------------------------------------------------------------
140  * ip_registry_remove:  Remove an entry from the IP registry
141  *--------------------------------------------------------------------------*/
142 static void ip_registry_remove(struct IPRegistryEntry* entry) 
143 {
144   unsigned int bucket = ip_registry_hash(entry->addr);
145
146   if (hashTable[bucket] == entry)
147     hashTable[bucket] = entry->next;
148   else {
149     struct IPRegistryEntry *prev;
150
151     for (prev = hashTable[bucket]; prev; prev = prev->next) {
152       if (prev->next == entry) {
153         prev->next = entry->next;
154         break;
155       }
156     }
157   }
158 }
159  
160
161 /*----------------------------------------------------------------------------
162  * ip_registry_new_entry():  Creates and initializes an IP Registry entry.
163  *                           NOW ALSO ADDS IT TO THE LIST! --ZS
164  *--------------------------------------------------------------------------*/
165 static struct IPRegistryEntry *ip_registry_new_entry(unsigned int addr, int attempt)
166 {
167   struct IPRegistryEntry* entry = freeList;
168
169   if (entry)
170     freeList = entry->next;
171   else
172     entry = (struct IPRegistryEntry *)MyMalloc(sizeof(struct IPRegistryEntry));
173
174   assert(0 != entry);
175
176   memset(entry, 0, sizeof(struct IPRegistryEntry));
177   entry->last_connect = NOW;     /* Seconds since last connect attempt */
178   entry->connected    = 1;       /* connected clients for this IP */
179   entry->attempts     = attempt; /* Number attempts for this IP        */
180   entry->addr         = addr;    /* Entry's IP Address                 */
181
182   ip_registry_add(entry);
183
184   return entry;
185 }
186
187
188 /*----------------------------------------------------------------------------
189  * ip_registry_delete_entry:  Frees an entry and adds the structure to a list
190  *                            of free structures.  (We should probably reclaim
191  *                            the freelist every once in a while!  This is
192  *                            potentially a way to DoS the server...  -ZS)
193  *--------------------------------------------------------------------------*/
194 static void ip_registry_delete_entry(struct IPRegistryEntry *entry)
195 {
196   if (entry->target)
197     MyFree(entry->target);
198
199   entry->next = freeList;
200   freeList = entry;
201 }
202
203
204 /*----------------------------------------------------------------------------
205  * ip_registry_update_free_targets:  
206  *--------------------------------------------------------------------------*/
207 static unsigned int ip_registry_update_free_targets(struct IPRegistryEntry  *entry)
208 {
209   unsigned int free_targets = STARTTARGETS;
210
211   if (entry->target) {
212     free_targets = (entry->target->count +
213                     (CONNECTED_SINCE(entry) / TARGET_DELAY));
214
215     if (free_targets > STARTTARGETS)
216       free_targets = STARTTARGETS;
217
218     entry->target->count = free_targets;
219   }
220
221   return free_targets;
222 }
223
224
225 /*----------------------------------------------------------------------------
226  * ip_registry_expire_entry:  expire an IP entry if it needs to be.  If an
227  *                            entry isn't expired, then also check the target
228  *                            list to see if it needs to be expired.
229  *--------------------------------------------------------------------------*/
230 static void ip_registry_expire_entry(struct IPRegistryEntry *entry)
231 {
232   /*
233    * Don't touch this number, it has statistical significance
234    * XXX - blah blah blah
235    * ZS - Just -what- statistical significance does it -have-?
236    * Iso - Noone knows, we've just been told not to touch it.
237    */
238   if (CONNECTED_SINCE(entry) > 120 && 0 != entry->target) {
239     MyFree(entry->target);
240     entry->target = 0;
241   }
242   if (CONNECTED_SINCE(entry) > 600) {
243     ip_registry_remove(entry);
244     ip_registry_delete_entry(entry);
245   }
246 }
247
248
249 /*----------------------------------------------------------------------------
250  * ip_registry_expire:  Expire all of the needed entries in the hash table
251  *--------------------------------------------------------------------------*/
252 void ip_registry_expire(void)
253 {
254   struct IPRegistryEntry *entry;
255   struct IPRegistryEntry *entry_next;
256   static time_t   next_expire = 0;
257   int i;
258
259   /* Only do this if we're ready to */
260   if (next_expire >= CurrentTime)
261     return;
262
263   for (i = 0; i < IP_REGISTRY_TABLE_SIZE; ++i) {
264     for (entry = hashTable[i]; entry; entry = entry_next) {
265       entry_next = entry->next;
266       if (0 == entry->connected)
267         ip_registry_expire_entry(entry);
268     }
269   }
270
271   next_expire = CurrentTime + 60;
272 }
273
274
275 /*----------------------------------------------------------------------------
276  *
277  * Event:
278  *   A new connection was accept()-ed with IP number `cptr->ip.s_addr'.
279  *
280  * Action:
281  *   Update the IPcheck registry.
282  *   Return:
283  *     1 : You're allowed to connect.
284  *     0 : You're not allowed to connect.
285  *
286  * Throttling:
287  *
288  * A connection should be rejected when a connection from the same IP
289  * number was received IPCHECK_CLONE_LIMIT times before this connect
290  * attempt, with reconnect intervals of IPCHECK_CLONE_PERIOD seconds
291  * or less.
292  *
293  * Free target inheritance:
294  *
295  * When the client is accepted, then the number of Free Targets
296  * of the cptr is set to the value stored in the found IPregistry
297  * structure, or left at STARTTARGETS.  This can be done by changing
298  * cptr->nexttarget to be `now - (TARGET_DELAY * (FREE_TARGETS - 1))',
299  * where FREE_TARGETS may range from 0 till STARTTARGETS.
300  *--------------------------------------------------------------------------*/
301 int ip_registry_check_local(unsigned int addr, time_t *next_target_out)
302 {
303   struct IPRegistryEntry *entry        = ip_registry_find(addr);
304   unsigned int free_targets = STARTTARGETS;
305  
306   assert(0 != next_target_out);
307
308   /* If they've never connected before, let them on */
309   if (0 == entry) {
310     Debug((DEBUG_DEBUG,"IPcheck: Local user allowed - unseen"));
311     entry = ip_registry_new_entry(addr, 1);
312     return 1;
313   }
314   
315   /* Keep track of how many people have connected */
316   entry->connected++;
317
318   /* Do not allow more than 250 connects from a single IP, EVER. */
319   if (250 <= entry->connected) {
320     Debug((DEBUG_DEBUG,"IPcheck: Local user disallowed - Too many connections"));
321     entry->connected--;
322     return 0;
323   }
324
325   /* If our threshhold has elapsed, reset the counter so we don't throttle,
326    * IPCHECK_CLONE_LIMIT connections every IPCHECK_CLONE_PERIOD
327    */
328   if (CONNECTED_SINCE(entry) > IPCHECK_CLONE_PERIOD) {
329     entry->attempts = 0;
330     entry->last_connect = NOW;
331   }
332
333   /* Count the number of recent attempts */ 
334   entry->attempts++;
335   
336   if (250 <= entry->attempts)
337     --entry->attempts;  /* Disallow overflow */
338
339
340   free_targets = ip_registry_update_free_targets(entry);
341
342   /* Have they connected less than IPCHECK_CLONE_LIMIT times && next_target_out */
343   if (entry->attempts < IPCHECK_CLONE_LIMIT && next_target_out) {
344       *next_target_out = CurrentTime - (TARGET_DELAY * free_targets - 1);
345       entry->last_connect = NOW;
346       Debug((DEBUG_DEBUG,"IPcheck: Local user allowed"));
347       return 1;
348   }
349   
350   /* If the server is younger than IPCHECK_CLONE_DELAY then the person
351    * is allowed on.
352    */
353   if ((CurrentTime - me.since) < IPCHECK_CLONE_DELAY) {
354     Debug((DEBUG_DEBUG,"IPcheck: Local user allowed during server startup"));
355     return 1;
356   }
357   
358   /* Otherwise they're throttled */
359   entry->connected--;
360   Debug((DEBUG_DEBUG,"IPcheck: Throttling local user"));
361   return 0;
362 }
363
364 /*
365  * Add someone to the ip registry without throttling them.
366  * This is used for server connections.
367  */
368 void ip_registry_add_local(unsigned int addr)
369 {
370   struct IPRegistryEntry *entry        = ip_registry_find(addr);
371  
372   /* If they've never connected before, let them on */
373   if (0 == entry) {
374     Debug((DEBUG_DEBUG,"IPcheck: Local user allowed - unseen"));
375     entry = ip_registry_new_entry(addr, 1);
376     return;
377   }
378   
379   /* Keep track of how many people have connected */
380   entry->connected++;
381
382   assert(250 <= entry->connected);
383
384   return;
385 }
386
387 /*----------------------------------------------------------------------------
388  * ip_registry_remote_connect
389  *
390  * Does anything that needs to be done once we actually have a client
391  * structure to play with on a remote connection.
392  * returns:
393  *  1 - allowed to connect
394  *  0 - disallowed.
395  *--------------------------------------------------------------------------*/
396 int ip_registry_remote_connect(struct Client *cptr)
397 {
398   struct IPRegistryEntry *entry        = ip_registry_find(cptr->ip.s_addr);
399   assert(0 != cptr);
400
401   /* If they've never connected before, let them on */
402   if (0 == entry) {
403     entry = ip_registry_new_entry(cptr->ip.s_addr, 1);
404     SetIPChecked(cptr);
405     Debug((DEBUG_DEBUG,"IPcheck: First remote connection.  connected=%i",entry->connected));
406     return 1;
407   }
408   
409   /* Keep track of how many people have connected */
410   entry->connected++;
411   SetIPChecked(cptr);
412
413   /* Do not allow more than 250 connections from one IP.
414    * This can happen by having 128 clients on one server, and 128 on another
415    * and then the servers joining after a netsplit
416    */ 
417   if (250 <= entry->connected) {
418     sendto_ops("IPcheck Ghost! [%s]",inet_ntoa(cptr->ip));
419     Debug((DEBUG_DEBUG,"IPcheck: Too many connected from IP: %i",entry->connected));
420     return 0;
421   }
422   
423   Debug((DEBUG_DEBUG,"IPcheck: %i people connected",entry->connected));
424   
425   /* They are allowed to connect */
426   return 1;
427 }
428
429 /*----------------------------------------------------------------------------
430  * IPcheck_connect_succeeded
431  *
432  * Event:
433  *   A client succeeded to finish the registration.
434  *
435  * Finish IPcheck registration of a successfully, locally connected client.
436  *--------------------------------------------------------------------------*/
437 void ip_registry_connect_succeeded(struct Client *cptr)
438 {
439   unsigned int free_targets     = STARTTARGETS;
440   struct IPRegistryEntry *entry;
441
442   assert(cptr);
443
444   entry = ip_registry_find(cptr->ip.s_addr);
445
446
447   assert(entry);
448
449   if (entry->target) {
450     memcpy(cptr->targets, entry->target->targets, MAXTARGETS);
451     free_targets = entry->target->count;
452   }
453
454   sendcmdto_one(&me, CMD_NOTICE, cptr, "%C :connected %u attempts %u/%u free targets %u/%u%s"
455                 " IPcheck: %s",
456                 cptr, entry->connected, entry->attempts, IPCHECK_CLONE_LIMIT,
457                 free_targets, STARTTARGETS, 
458                 ((entry->target) ? " [Inherited Targets]" : ""), 
459                 ((CurrentTime - me.since) < IPCHECK_CLONE_DELAY) ? "Disabled" : "Enabled");
460                 
461   SetIPChecked(cptr);
462 }
463
464
465 /*----------------------------------------------------------------------------
466  * IPcheck_disconnect
467  *
468  * Event:
469  *   A local client disconnected.
470  *
471  * Action:
472  *   Update the IPcheck registry.
473  *   Remove all expired IPregistry structures from the hash bucket
474  *     that belongs to this clients IP number.
475  *--------------------------------------------------------------------------*/
476 void ip_registry_local_disconnect(struct Client *cptr)
477 {
478   struct IPRegistryEntry *entry;
479   unsigned int free_targets;
480
481   assert(0 != cptr);
482
483   entry = ip_registry_find(cptr->ip.s_addr);
484
485   Debug((DEBUG_DEBUG,"IPcheck: Local Disconnect"));
486         
487   assert(IsIPChecked(cptr));
488   
489   assert(entry);
490
491   assert(entry->connected > 0);
492   
493   if (entry->connected > 0) {
494     entry->connected--;
495   }
496
497   /*
498    * If this was the last one, set `last_connect' to disconnect time
499    * (used for expiration)   Note that we reset attempts here as well if our
500    * threshhold hasn't been crossed.
501    */
502   if (0 == entry->connected) {
503     ip_registry_update_free_targets(entry);
504     entry->last_connect = NOW;
505   }
506   
507   assert(MyConnect(cptr));
508
509   if (0 == entry->target) {
510     entry->target = (struct IPTargetEntry *)MyMalloc(sizeof(struct IPTargetEntry));
511     assert(0 != entry->target);
512     entry->target->count = STARTTARGETS;
513   }
514   memcpy(entry->target->targets, cptr->targets, MAXTARGETS);
515
516   /*
517    * This calculation can be pretty unfair towards large multi-user hosts,
518    * but there is "nothing" we can do without also allowing spam bots to
519    * send more messages or by drastically increasing the ammount of memory
520    * used in the IPregistry.
521    *
522    * The problem is that when a client disconnects, leaving no free targets,
523    * then the next client from that IP number has to pay for it (getting no
524    * free targets).  But ALSO the next client, and the next client, and the
525    * next client etc - until another client disconnects that DOES leave free
526    * targets.  The reason for this is that if there are 10 SPAM bots, and
527    * they all disconnect at once, then they ALL should get no free targets
528    * when reconnecting.  We'd need to store an entry per client (instead of
529    * per IP number) to avoid this.  
530    */
531   if (cptr->nexttarget < CurrentTime)
532     free_targets = (CurrentTime - cptr->nexttarget) / TARGET_DELAY + 1;
533   else
534     free_targets = 0;
535
536   /* Add bonus, if you've been connected for more than 10 minutes you
537    * get a free target every TARGET_DELAY seconds.
538    * this is pretty fuzzy, but it will help in some cases. 
539    */
540   if ((CurrentTime - cptr->firsttime) > 600)
541     free_targets += (CurrentTime - cptr->firsttime - 600) / TARGET_DELAY;
542
543   /* Finally, store smallest value for Judgement Day */
544   if (free_targets < entry->target->count)
545     entry->target->count = free_targets;
546   
547 }
548
549 /*----------------------------------------------------------------------------
550  * ip_registry_remote_disconnect
551  *
552  * Event:
553  *   A remote client disconnected.
554  *
555  * Action:
556  *   Update the IPcheck registry.
557  *   Remove all expired IPregistry structures from the hash bucket
558  *     that belongs to this clients IP number.
559  *--------------------------------------------------------------------------*/
560 void ip_registry_remote_disconnect(struct Client *cptr)
561 {
562   struct IPRegistryEntry *entry;
563
564   assert(0 != cptr);
565
566   entry = ip_registry_find(cptr->ip.s_addr);
567   
568   assert(entry);
569   
570   assert(entry->connected > 0);
571   Debug((DEBUG_DEBUG,"IPcheck: Remote Disconnect"));
572
573   if (entry->connected > 0) {
574     entry->connected--;
575   }
576
577   /*
578    * If this was the last one, set `last_connect' to disconnect time
579    * (used for expiration)   Note that we reset attempts here as well if our
580    * threshhold hasn't been crossed.
581    */
582   if (0 == entry->connected) {
583     ip_registry_update_free_targets(entry);
584     entry->last_connect=NOW;
585   }
586 }
587
588 /*----------------------------------------------------------------------------
589  * IPcheck_nr
590  *
591  * Returns number of clients with the same IP number
592  *--------------------------------------------------------------------------*/
593 int ip_registry_count(unsigned int addr)
594 {
595   struct IPRegistryEntry *entry = ip_registry_find(addr);
596   return (entry) ? entry->connected : 0;
597 }