/*
 *
 *                                  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
 * 
 *  mem.c - contains shared memory and semaphore control logic
 * 
 *  Multi-process:
 *  Initializing and accesing shared memory:
 *  ----------------------------------------
 *  - Create the shared segment
 *  - Attach each process to the segment (in our case, the hunter child 
 *    process will inherit a pointer to the block)
 *  - Grab a semaphore 
 *  - Lock the semaphore; Manipulate shared segment; unlock the semaphore 
 *
 *
 *  Multi-threaded:
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>

#define SHMKEY 242 	            /* Shared memory key */
#define SEMKEY 424 	            /* Semaphore key */
#define PERMS 0666                  /* Shared Memory Permissions */
#define MAXNODES 512		    /* Maximum number of nodes */
#define ADDMSG "+"
#define DELMSG "-"

int semid;                          /* Semaphore ID */

struct sembuf lock[2]={{0,0,0},{0,1,SEM_UNDO}};         
                                    /* wait for sem#0 to become 0 then 
                                       increment sem#0 by 1 */
struct sembuf ulock[1]={{0,-1,(IPC_NOWAIT|SEM_UNDO)}};  
                                    /* decrement sem#0 by 1 (sets it to 0) */

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;

static struct connectionInfo{       /* Simple tuple structure */
    unsigned long saddr;            /* Source IP */
    unsigned long daddr;            /* Destination IP */
    unsigned short sport;           /* Source TCP Port */
    unsigned short dport;           /* Destination TCP Port */
}*cinfo=0;

extern int verbosity;

/*
 *  Creates the shared memory segment then attaches it; then creates a binary 
 *  semaphore to guarantee exclusive access.  Clears the structure array.
 *  Dumps some info.    
 *  Much credit to Richard Stevens and Jeff Thompson.
 */

void powerup(){
	
    void locks();
    void ulocks();
    void cleardb();

    int shmid;              	    /* Shared memory segment id */
    int len;
	
    len=sizeof(struct connectionInfo)*MAXNODES;

                                    /* Request a shared memory segment */
    if((shmid=shmget(SHMKEY,len,IPC_CREAT))<0){			
        if(verbosity)perror("(powerup) shared memory segment allocation error [fatal]");
        exit(1);
    }
                                    /* Get one semaphore to perform shared 
                                       memory locking with */
    if((semid=semget(SEMKEY,1,IPC_CREAT|PERMS))<0){        	
        if(verbosity)perror("(powerup) semaphore allocation error [fatal]");
	exit(1);        
    }
                                    /* Attach to the shared memory segment */
    cinfo=(struct connectionInfo *)shmat(shmid,0,0);		

    cleardb();
}

/*
 *  Release the shared memory segment.
 */

void powerdown(){

    void locks();
    void ulocks();

    locks();
    shmdt((char *)cinfo);           /* Dettach the segment. */
    ulocks();
}

/*
 *  Locks the semaphore so the caller can access the shared memory segment.  
 *  This is an atomic operation.
 */

void locks(){
    if(semop(semid,&lock[0],2)<0){
        if(verbosity)perror("(locks) could not lock semaphore [fatal]");
        exit(1);
    }
}
        
/*
 *  Unlocks the semaphore so the caller can access the shared memory segment. 
 *  This is an atomic operation.
 */

void ulocks(){
    if(semop(semid,&ulock[0],1)<0){
        if(verbosity)perror("(ulocks) could not unlock semaphore [fatal]");
        exit(1);
    }
}


/* 
 *  Add a connection to our list.  Linear search of the WHOLE list to see if 
 *  it's already there (which IT SHOULDN'T BE...), if not, add it in the
 *  first open slot.
 */

char *addc(iphp,tcphp)
struct iphdr *iphp;
struct tcphdr *tcphp;
{
    void locks();
    void ulocks();
        
    int i=0;        
			                /* A wonderfully inefficient linear 
                                           search for duplicates */

    locks();				/* Lock shared memory segment */
    for(;i<MAXNODES;i++)if(iphp->saddr==cinfo[i].saddr&&iphp->daddr==cinfo[i].daddr&&tcphp->source==cinfo[i].sport&&tcphp->dest==cinfo[i].dport){
        ulocks();
	return(0);                      /* Opps.  Found a duplicate */
    }
        		                /* Find available slot */
    for(i=0;i<MAXNODES;i++){
	if(cinfo[i].saddr)continue;
	else{
	    cinfo[i].saddr=iphp->saddr;
	    cinfo[i].daddr=iphp->daddr;
	    cinfo[i].sport=tcphp->source;
            cinfo[i].dport=tcphp->dest;
            ulocks();
	    return(ADDMSG);
	}
    }			                /* Control falls here if array is 
                                           full (which is indicative of
                                           a BUSY NETWORK!@*/
    ulocks();
    return(0);		                
}


/* 
 *  Remove a connection from our list.  Linear search until we find a 
 *  correspoding entry, or we hit the end of the list.
 */

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

    int i=0;        

    locks();                        /* Lock shared memory segment */
    for(;i<MAXNODES;i++)if(iphp->saddr==cinfo[i].saddr&&iphp->daddr==cinfo[i].daddr&&tcphp->source==cinfo[i].sport&&tcphp->dest==cinfo[i].dport){
	bzero(&cinfo[i],sizeof(cinfo[i]));
	ulocks();
        return(DELMSG);		    /* Inform caller of success */
    }
    ulocks();
    return(0);		            /* hmm.  Wierd.   */
}


/* 
 *  Dump the connection list.
 */

float dumpc()
{
    void locks();
    void ulocks();
    char *hostLookup(unsigned long);

    int i=0;        
    float j=0;

    locks();
    for(;i<MAXNODES;i++)if(cinfo[i].saddr){
        fprintf(stderr,"(%d)\t %s [%d]\t-->\t %s [%d]\n",i+1,hostLookup(cinfo[i].saddr),ntohs(cinfo[i].sport),hostLookup(cinfo[i].daddr),ntohs(cinfo[i].dport));
        j++;
    }
    ulocks();
    if(!j)return(0);
    return(((j/MAXNODES)*100));     /* % utilization */
}


/* 
 *  Check for a connection by index number.  Really only here to make sure the
 *  connection hasn't been deleted since dump() was called....  I think I
 *  will deprecate this function in future versions...
 */
   
struct connectionInfo *checkc(target)
int target;
{       
    void locks();
    void ulocks();

    static struct connectionInfo tmp;
        
    locks();				    /* Lock shared memory segment */
    if(cinfo[--target].saddr){			
	memcpy(&tmp,&cinfo[target],sizeof(tmp));
	ulocks();
	return(&tmp);			
    }
    ulocks();				    /* Nope.  Not there */
    return((struct connectionInfo *)0);
}


/*
 *  Clear the connection database
 */

void cleardb(){

    void locks();
    void ulocks();

    int i=0;

    locks();
    for(;i<MAXNODES;i++)bzero(&cinfo[i],sizeof(cinfo[i]));
    ulocks();     
}
