/*
Received: from stilton.Cisco.COM by mail.bbnplanet.com id aa13838;
          7 Nov 96 23:35 EST
Received: from cisco.com (localhost.cisco.com [127.0.0.1]) by stilton.cisco.com (8.6.12/8.6.5) with ESMTP id UAA22855 for <jhawk@bbnplanet.com>; Thu, 7 Nov 1996 20:34:01 -0800
Message-Id: <199611080434.UAA22855@stilton.cisco.com>
To: John Hawkinson <jhawk@bbnplanet.com>
Subject: Re: Another stuck tcp connection? 
In-reply-to: Message from John Hawkinson <jhawk@bbnplanet.com> 
   of "Thu, 07 Nov 1996 23:11:37 EST." <9611072311.aa03056@poblano.bbnplanet.com> 
Mime-Version: 1.0
Content-Type: Text/Plain; charset=us-ascii
Date: Thu, 07 Nov 1996 20:34:01 -0800
From: Andy Heffernan <ahh@cisco.com>
Status: RO

/*
 * rst -- reset a TCP connection from afar
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/tcp.h>
#include <netinet/tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <errno.h>

extern int optarg, optind;

char *usage = "Usage: %s [-i <num>] [-u <num>] [-[afprs]] src sport dst dport seq ack [byte]\n";

int debug = 0;

main(argc, argv)
	int argc;
	char *argv[];
{
	char *progname;
	struct in_addr dst, src;
	u_short sport, dport;
	u_long seq, ack;
	int iter, urg;
	int ch;
	int flags;
	u_char *data;
	int datalen;

	progname = argv[0];

	iter = 1;
	flags = 0;
	urg = 0;
	while ((ch = getopt(argc, argv, "adfi:prsu:")) != -1) {
		switch (ch) {
		case 'a':
			flags |= TH_ACK;
			break;
		case 'd':
			debug = 1;
			break;
		case 'f':
			flags |= TH_FIN;
			break;
		case 'p':
			flags |= TH_PUSH;
			break;
		case 'r':
			flags |= TH_RST;
			break;
		case 's':
			flags |= TH_SYN;
			break;
		case 'u':
			flags |= TH_URG;
			urg = strtol(optarg, NULL, 10);
			break;
		case 'i':
			iter = strtol(optarg, NULL, 10);
			break;
		default:	
			fprintf(stderr, usage, progname);
			exit(1);
			break;
		}
	}
	argc -= optind;
	argv += optind;

	if (argc < 6) {
		fprintf(stderr, usage, progname);
		exit(1);
	}

	if (!inet_aton(argv[0], &src)) {
		struct hostent *host;
		if ((host = gethostbyname(argv[0])) == NULL) {
			fprintf(stderr, "host %s not found\n", argv[0]);
			exit(1);
		}
		bcopy((char *) host->h_addr, (char *) &src, host->h_length);
	}

	sport = atoi(argv[1]);

	if (!inet_aton(argv[2], &dst)) {
		struct hostent *host;
		if ((host = gethostbyname(argv[2])) == NULL) {
			fprintf(stderr, "host %s not found\n", argv[2]);
			exit(1);
		}
		bcopy((char *) host->h_addr, (char *) &dst, host->h_length);
	}

	dport = atoi(argv[3]);

	seq = strtol(argv[4], NULL, 10);
	ack = strtol(argv[5], NULL, 10);

	if (argc > 6) {
		int i, length;

		data = argv[6];
		datalen = strlen(data);
		length = datalen;
		for (i = 0; i < length; i++) {
			if (data[i] == '^')	/* stupid, but oh well */
				data[i] = 0;
		}
	} else {
		data = NULL;
		datalen = 0;
	}

	while (iter--)
		tcp_packet(src, dst, sport, dport, seq++, ack, urg, flags,
				data, datalen);

	exit(0);
}

tcp_packet(src, dst, sport, dport, seq, ack, urg, flags, data, datalen)
	struct in_addr src, dst;
	u_short sport, dport;
	u_long seq, ack;
	u_short urg;
	int flags;
	u_char *data;
	int datalen;
{
	int s;
	struct tcpiphdr *tcpip;
	struct sockaddr_in where, me;
	int on = 1; 
	struct ip *ip;
	u_short sum;
	int packet_size;
	u_char *packet, *payload;

	packet_size = sizeof(struct tcpiphdr) + datalen;
	if ((packet = malloc(packet_size)) == NULL) {
		perror("malloc");
		exit(1);
	}
	bzero(packet, packet_size);
	tcpip = (struct tcpiphdr *) packet;
	payload = (u_char *) (tcpip + 1);
	bcopy(data, payload, datalen);

	if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
		perror("socket");
		exit(1);
	}
#ifdef IP_HDRINCL
	if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&on,
		       sizeof(on)) < 0) {
		perror("IP_HDRINCL");
		return(-1);
	}
#endif /* IP_HDRINCL */

	bzero(&where, sizeof(where));
	where.sin_family = AF_INET;
	where.sin_addr = dst;

	/* Pseudo-header */
	tcpip->ti_pr = IPPROTO_TCP;
	tcpip->ti_len = htons(sizeof(struct tcphdr) + datalen);
	tcpip->ti_src = src;
	tcpip->ti_dst = dst;
	/* TCP header */
	tcpip->ti_sport = htons(sport);
	tcpip->ti_dport = htons(dport);
	tcpip->ti_seq = htonl(seq);
	tcpip->ti_ack = htonl(ack);
	tcpip->ti_off = sizeof(struct tcphdr) >> 2;
	tcpip->ti_flags = flags;
	tcpip->ti_win = htons(1024);
	tcpip->ti_sum = htons(0);
	tcpip->ti_urp = htons(urg);
	tcpip->ti_sum = in_cksum((u_short *) tcpip, packet_size);
	if (debug) {
		int i;

		printf("checksum %04x\n", tcpip->ti_sum);
		for (i = 0; i < packet_size; i++) {
			printf("%02x ", ((u_char *)tcpip)[i]);
			if (!((i + 1) % 16))
				putchar('\n');
		}
		if (i % 16)
			putchar('\n');
	}

	ip = (struct ip *) &tcpip->ti_i;
	ip->ip_v = 4;
	ip->ip_hl = 5;
	ip->ip_tos = 0;
	/* ip_len has the wrong byte order but the kernel wants it that way */
	ip->ip_len = sizeof(struct tcpiphdr) + datalen;
	ip->ip_id = htons(69);
	ip->ip_off = htons(0);
	ip->ip_ttl = 255;
	ip->ip_p = IPPROTO_TCP;
	ip->ip_sum = 0;
	ip->ip_src = src;
	ip->ip_dst = dst;
	ip->ip_sum = in_cksum((u_short *) ip, sizeof(struct ip));

again:
	if (sendto(s, ip, packet_size, 0, (struct sockaddr *) &where,
		   sizeof(struct sockaddr_in)) == -1) {
		if (errno == ENOBUFS) {
			sleep(1);
			goto again;
		}
		perror("sendto");
		return(-1);
	}

	close(s);
	free(packet);
	return(0);
}

/*
 * in_cksum --
 *	Checksum routine for Internet Protocol family headers (C Version)
 */
int
in_cksum(addr, len)
	u_short *addr;
	int len;
{
	u_short *w = addr;
	u_long 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 (len > 1)  {
		sum += *w++;
		len -= 2;
	}

	/* mop up an odd byte, if necessary */
	if (len == 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);
}

[48;1H[K
