/* 
 * pest.c, by |WARL0RD|
 *      05/2002
 * --------------------------------------------
 * This little utility relays to a host via a proxy, 
 * and then binds a local port so the datapipe
 * can very easily be accessed. 
 * The tunnel will be (re)build for every 
 * client that accesses it, until it
 * receives some sort of a signal(like ^C).
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <ctype.h>
#include <sys/wait.h>


#define MAXDATASIZE 80
#define VERSION "0.16"




int recvbuf[80],recvbuf2[160],recvbuf3[160];
char proxyhost[255],host_add[16],compare[30];
int bindport,sock,masterfd,servsock,hostindex=0;
struct sockaddr_in tosin,fromsin,mastersin;


/********************************************************************/

int usage(char *argv) {
printf("Usage: %s proxy-ip proxy-port dst-host dst-port port-nr-to-bind.\n",argv);
exit(0);
return 1;
}


/***************************************************/

void sighandler(int pid) {
int i,status;
i=waitpid(-1,&status,0);
return;
}


/*************************************************************************/
/* managing the data exchange between client and server */


void pipemode() {

int readnmb,readnmb2;
fd_set fdset;
int ret;


while(1) 
  {
    FD_ZERO(&fdset);
    FD_SET(sock,&fdset); FD_SET(masterfd,&fdset);
    if((ret=select(FD_SETSIZE,&fdset,NULL,NULL,NULL))==-1) exit(31337); 
 
    if(FD_ISSET(sock,&fdset))
      {
     memset(recvbuf3,0,sizeof(recvbuf3));
      if((readnmb = read(sock,recvbuf3,150))<1)
        {
          if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
          else 
            {
              close(sock);
              close(masterfd);
              exit(1);
            }
           
        }
      send(masterfd,recvbuf3,readnmb,0);
      }
   
    if(FD_ISSET(masterfd,&fdset))
      {
      memset(recvbuf2,0,sizeof(recvbuf2));
      if((readnmb2 = read(masterfd,recvbuf2,150)) < 1)
        {
          if(errno==EWOULDBLOCK||errno==EAGAIN) continue;
          else 
            {
              close(masterfd);
              close(sock);
              exit(1);
            }
            
        }   
      send(sock,recvbuf2,readnmb2,0);
      }   
  }
  exit(0);
}

/******************************************************************************/
/*Connecting to the proxy and relaying to the final host*/

void pre_pipemode(char *thost,int tport,int pport)
  {
    int sslen;
    char sendstring[60];
    struct hostent *he;

  
    printf("Initiating connection to %s:%d\n",thost,tport);
    if((sock=socket(AF_INET,SOCK_STREAM,0))==-1)
      {
        printf("socket call failed.\n");
        fflush(stdout);
        exit(1);
      }

     if((he = gethostbyname(proxyhost))==NULL)
       {
         printf("Unable to resolve %s\n",proxyhost);
         exit(1);
       }
        
      tosin.sin_family=AF_INET;
      tosin.sin_port=htons(pport);
      tosin.sin_addr= *((struct in_addr *)he->h_addr);
      bzero(&(tosin.sin_zero),8);
      if(connect(sock,(struct sockaddr *)&tosin,sizeof(struct sockaddr)) ==-1)
        {
        printf("Cannot connect().\n");
        close(masterfd);
        exit(1);
        }

      printf("Successfully connected to the proxy: %s.\n",proxyhost);

 

    memset(sendstring,0,sizeof(sendstring));
    sprintf(sendstring,"CONNECT %s:%d HTTP/1.0\n\n",thost,tport);  
    sslen=strlen(sendstring);
    send(sock,sendstring,sslen,0);
    
    memset(sendstring,0,sizeof(sendstring));
    memset(recvbuf,0,sizeof(recvbuf));
    recv(sock,recvbuf,71,0);
    if(strncmp((char*)recvbuf,"HTTP/1.0 200 Connection established",strlen("HTTP/1.0 200 Connection established"))!=0)
      {
        printf("Couldn't establish connection to the target.\n");
        printf("RECEIVED: %s\n",(char*)recvbuf);
        exit(1);
      }

    printf("Connected to the target host. The tunnel has been built. The port is %d.\n\n",bindport);

    pipemode();
  }

/**********************************************************************/
/**********************************************************************/
/**********************************************************************/



int main(int argc, char **argv) {
char thost[255];
int pid,sock_size,tport;

printf("\npest.c %s by |WARL0RD|\n",VERSION);
printf("\t05/2002\n");
printf("-------------------------------\n\n");

if(argc < 6) { usage(argv[0]); }

signal(SIGCHLD,sighandler);


memset(proxyhost,0,sizeof(proxyhost));
strncpy(proxyhost,argv[1],sizeof(proxyhost));


memset(thost,0,sizeof(thost));
strncpy(thost,argv[3],sizeof(thost));
tport = atoi(argv[4]);


bindport=atoi(argv[5]);


        /*Binding the local port*/
	
 if((servsock=socket(AF_INET,SOCK_STREAM,0))==-1)
   {
     printf("Cannot bind the socket for the port.\n");
     exit(1);
   }
 
 fromsin.sin_family=AF_INET; /*Filling the struct for the port to bind*/
 fromsin.sin_addr.s_addr=htonl(INADDR_ANY);
 fromsin.sin_port=htons(bindport);
 bzero(&(fromsin.sin_zero),8);
 
 if(bind(servsock,(struct sockaddr *)&fromsin,sizeof(struct sockaddr)) == -1)
   {
     printf("Cannot bind port %d.\n",bindport);
     exit(1);
   }

if(listen(servsock,10) == -1)
  {
    printf("Cannot listen().\n");
    exit(1);
  } 

printf("Local port bound and ready. Access it on port %d\n\n",bindport);

while(1) /* M A I N L O O P   S T A R T*/
{
  sock_size=sizeof(struct sockaddr_in);
  if((masterfd=accept(servsock,(struct sockaddr *)&mastersin,&sock_size)) == -1)
   {
    printf("accept() failed.\n");
    exit(1);
   }
   else
   {
    inet_ntoa(mastersin.sin_addr);
    pid = fork();
    if(pid==0) 
      {
        close(servsock);
        pre_pipemode(argv[3],atoi(argv[4]),atoi(argv[2]));
      }     
    close(masterfd);
   }    
 } /*M A I N L O O P   E N D*/

exit(0);
}

