/*****************************************************************
 * PTlink IRCd is (C) CopyRight PTlink Coders Team 1999-2000     *
 * http://www.ptlink.net/Coders - coders@PTlink.net              *
 * This program is distributed under GNU Public License          *
 * Please read the file COPYING for copyright information.       *
 *****************************************************************
 *   $Id: spoof.c,v 1.4 2001/02/10 19:00:43 jpinto Exp $ 
 
  File: throttle.c
  Desc: host spoofing routines
  Author: Lamego@PTlink.net
*/
#include "common.h"
#include "s_log.h"
#include "irc_string.h"
#include "m_commands.h"
#include "ircd.h"
#include "send.h"
#include "client.h"
#include "numeric.h"
#include "dconf.h"
#include "conf_vars.h"
#include "throttle.h"

#include <stdlib.h>
#include <string.h>

/* this is our hash table -- statically initialized to 0 */
static struct aThrottle *throttles[256];

void remove_clone_check(struct Client * cptr)
{
    register unsigned char *p = (unsigned char *) &cptr->ip.s_addr;
    register struct aThrottle *ptr = throttles[(p[0] + p[1] + p[2] + p[3]) & 0xff];

    if (cptr->ip.s_addr == 0)
	return;

    while (ptr && (cptr->ip.s_addr != ptr->ip.s_addr))
	ptr = ptr->next;

    if (ptr && (ptr->count > 1))
	ptr->count--;
}

/*
 * check_clones
 *
 * This function counts the number of clients with the same IP number
 * as cptr that connected less than CHECK_CLONE_PERIOD seconds ago. 
 * return value
 * -1: reject connections
 * 0: permit connections
 *
 * Based on the original (ircu) from Seks, Record and Run
 * fixed up by nikb <nikb@dal.net>
 */

int check_clones(struct Client * cptr, const char *remote)
{
    struct aThrottle **tscn, *tptr;
    unsigned char *p = (unsigned char *) &cptr->ip.s_addr;
    unsigned char hval = (unsigned char) (p[0] ^ p[1] ^ p[2] ^ p[3]) & 0xFF;
    tscn = &throttles[hval];

    if (cptr->ip.s_addr == 0)
		return 0;

	/* scan the hash for this host and clean expired entries meanwhile */
    while (*tscn && (cptr->ip.s_addr != (*tscn)->ip.s_addr)) 
	  {
		if ((*tscn)->last + CheckClonesPeriod < CurrentTime)
		  {
	  		tptr = *tscn;
/*
	  		if ((tptr->count == THROTTLE_SENTWARN) && ((*tscn)->last + CheckClonesDelay < CurrentTime))
			  {
				sendto_realops("Removing throttle from %s (%s)", tptr->connected, inetntoa((char *) &tptr->ip));
			  }
*/
			*tscn = tptr->next;				  
			free(tptr->connected);
	  		free(tptr);			  
		  } 
		else
		  tscn = &(*tscn)->next;
  	  }

    if ((tptr = *tscn))
	  {	/* There is a record for this host */		

		if (!(tptr->last + CheckClonesPeriod < CurrentTime)) 
		
		  {		/* not expired */
			tptr->last = CurrentTime;

	  		if (remote && !tptr->connected && (tptr->connected = (char *) MyMalloc(strlen(remote) + 1)))
			  strcpy(tptr->connected, remote);			

	  		if (tptr->count >= 0) 
			  {
				if (++tptr->count == CheckClonesLimit)
		  		tptr->count = THROTTLE_HITLIMIT;

				return 0;
	  		  }
			  
	  		if (tptr->count == THROTTLE_HITLIMIT) 
			  {
				sendto_realops_flags(FLAGS_REJ, "Throttling connections from %s (%s)", tptr->connected, inetntoa((char *) &tptr->ip));
				tptr->count = THROTTLE_SENTWARN;

		  		return -1;		
	  		  }			  
		  } 
		else 				
		  {
			
			tptr->last = CurrentTime;
/*			not needed with zlines - Lamego
			if ((tptr->count == THROTTLE_SENTWARN) && !(tptr->last + CheckClonesDelay < CurrentTime)) 
			  return 0;
*/
	  		if (tptr->count == THROTTLE_SENTWARN)
			  sendto_realops_flags(FLAGS_REJ, "Resetting throttle from %s (%s)", tptr->connected, inetntoa((char *) &tptr->ip));
	  
	  		tptr->count = 1;			

	  		if (remote && !tptr->connected && (tptr->connected = (char *) MyMalloc(strlen(remote) + 1)))
				strcpy(tptr->connected, remote);

	  		return 0;
		  }
  	  } 

    
  	else 
	  {			/* no record for the host, make one */
		tptr = (struct aThrottle *) MyMalloc(sizeof(struct aThrottle));
		tptr->ip = cptr->ip;
		tptr->next = throttles[hval];
		tptr->last = CurrentTime;
		tptr->count = 1;
		tptr->connected = NULL;

		if (remote && (tptr->connected = (char *) MyMalloc(strlen(remote) + 1)))
	      strcpy(tptr->connected, remote);

		throttles[hval] = tptr;
		return 0;
    }

    /* we should never get here, but just in case */
    return 0;
}
