/* IP/tcp_port Redirector * Redirect data from source A to dest C via B (this host), * thus overiding routing path in application layer. * This works like a proxy www server, but it works for * any port/application (w/o proxy cache of course) * I made this for J. Deliyannis who's connection with USA is * slow, thus by using this program he can connect to USA through greece * and have a fast connection ;-) * Ioannou Spiros Nov '97 * * Program tested under sunos 5.x * Can support MAXCHILDS connections to the same host simultaneously. * forks a new process for every connection. * * Change MAXCHILDS as you wish. */ #define MAXCHILDS 10 #include #include #include #include #include #include #include #include #include #include #include #include #include /* TODO list -Add child forking Done -Add capability to change DestHost via network without restarting daemon */ void childhdl(); char buffer[100000]; int lsd, a, b, i,Asd,Csd,len,we_full,we_child,cdown; int reconfigurable,Confsd,rConfsd; char desthost[64],destport[10]; struct sockaddr_in sa, sc,sconf; unsigned char in[2]; struct timeval tval; struct hostent *chost; fd_set inout_fds; main (int argc, char *argv[]) { int one=1; Asd=-1; Csd=-1; Confsd=-1; we_full=0; we_child=0; reconfigurable=0; cdown=1; if (argc != 4) { printf ("Usage: ipredirect localport desthost destport\n\tor\n"); printf ("Usage: ipredirect localport \"rec\" confport\n\n"); exit (-1); } else if (!strcmp(argv[2],"rec")) reconfigurable=1; else reconfigurable=0; if (reconfigurable) { printf("\nRunning in reconfigurable mode, connect to \n"); printf("confport %d to specify new destination address\n",atoi(argv[3])); } signal(SIGCHLD,childhdl); if (reconfigurable) { if ((Confsd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("conf:socket"); exit (1); } setsockopt(Confsd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); sconf.sin_family = AF_INET; sconf.sin_port = htons ((u_short) atoi (argv[3])); sconf.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (Confsd, (struct sockaddr *) &sconf, sizeof (sconf)) < 0) { perror ("conf:bind"); exit (2); } if (listen (Confsd, 1) < 0) { perror ("conf:listen"); exit (3); } len = sizeof (sconf); printf ("\nConfiguration port ready ... awaiting for connection\n"); } else { strcpy(desthost,argv[2]); strcpy(destport,argv[3]); } if (reconfigurable) if ((rConfsd = accept (Confsd, (struct sockaddr *) &sconf, &len)) < 0) { perror ("rConfsd:accept"); exit(4); } else { strcpy(buffer,"\nWelcome to ipredirector\n-----------------------\n"); strcat(buffer,"Please specify a destination host after each prompt in\n"); strcat(buffer,"the form : host port\nType help for help, or exit to quit\n\n"); strcat(buffer,"Destination > "); write (rConfsd,buffer,strlen(buffer)); newdest(); } /*Open the "A" socket*/ if ((lsd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("socket"); exit (1); } setsockopt(lsd,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one)); sa.sin_family = AF_INET; sa.sin_port = htons ((u_short) atoi (argv[1])); sa.sin_addr.s_addr = htonl (INADDR_ANY); if (bind (lsd, (struct sockaddr *) &sa, sizeof (sa)) < 0) { perror ("bind"); exit (2); } if (listen (lsd, 10) < 0) { perror ("listen"); exit (4); } len = sizeof (sa); strcpy (buffer, ""); printf ("daemon ready ...\n"); while (1) { fflush (stdout); tval.tv_sec = 0; tval.tv_usec = 0; /*50 microseconds*/ startselect: FD_ZERO (&inout_fds); /*Initialize file descriptors for select*/ /* Prepare for input from host A */ if (we_child && Asd > 0) FD_SET (Asd, &inout_fds); /* Prepare for input from host C */ if (we_child && Csd > 0) FD_SET (Csd, &inout_fds); /* Prepare to accept a connection to our socket */ if (!we_child) FD_SET (lsd, &inout_fds); if (!we_child && reconfigurable) FD_SET (rConfsd,&inout_fds); #ifdef TESTING printf("\nbefore select.. child:%d ",we_child); #endif /* Do a non-timeout select (interupt driven) to minimize load*/ do { i = select (64, &inout_fds, (fd_set *) 0, (fd_set *) 0, (struct timeval *)0/*&tval*/ ); #ifdef TESTING if (i==EINTR) printf("Select probably interrupted by SIGCHLD signal\n"); #endif } while(i==EINTR||i<0); #ifdef TESTING printf("after select=%d..child:%d\n",i,we_child); #endif if (FD_ISSET (rConfsd,&inout_fds)) { newdest(); printf("New destination is: %s %s\n",desthost,destport); } /*We are server, and full,and a new connection*/ if (FD_ISSET (lsd, &inout_fds) && we_full>=MAXCHILDS && !we_child) { if ((Asd = accept (lsd, (struct sockaddr *) &sa, &len)) < 0) { perror ("accept"); } else { /*deny connection*/ #ifdef TESTING printf ("\nRejected new connection -- server full,%d\n", Asd); printf ("Family=:%d , port=%d address: %s\n", sa.sin_family, ntohs (sa.sin_port), inet_ntoa (sa.sin_addr)); #endif strcpy (buffer, "\nServer full, sorry ;-).\n"); write (Asd, buffer, sizeof (buffer)); shutdown(Asd,2); close(Asd); Asd=-1; } } /*A new connection, ...*/ else if (FD_ISSET (lsd, &inout_fds) && we_full 0 && FD_ISSET (Asd, &inout_fds)) { bzero (buffer, sizeof (buffer)); /* read data from A */ b = read (Asd, buffer, sizeof (buffer)); #ifdef ALLTESTING printf ("buffer read from A is:#%s#=%d bytes\n", buffer, b); #endif /*If read failed : A closed connection*/ if (b <= 0) { /*Free A for a new connection */ shutdown (Asd, 2); close (Asd); /* Close C also to establish new connection * in a fresh manner */ shutdown (Csd, 2); close (Csd); Csd=-1; printf ("Closed connection to address: %s port=%d \n", inet_ntoa (sa.sin_addr),ntohs (sa.sin_port)); exit(0); #ifdef TESTING printf ("pid %d:quiting, A closed connection \n",getpid()); #endif } else { #ifdef ALLTESTING printf ("\nbuffer written to C is:#%s#=%d bytes\n", buffer, b); #endif /* write A data to C */ write (Csd, buffer, b); #ifdef DEBUG printf ("A to C: #%s#\n", buffer); #endif } } /*Transfer data from C to A*/ if (we_child && Csd > 0 && FD_ISSET (Csd, &inout_fds) && Asd>0 ) { bzero (buffer, sizeof (buffer)); #ifdef TESTING printf("\nReading from C..."); #endif /* read data from C*/ b = read (Csd, buffer, sizeof (buffer)); #ifdef TESTING printf("Ok, read %d bytes\n",b); #endif #ifdef ALLTESTING printf ("buffer read from C is:#%s#=%d bytes\n", buffer, b); #endif if (b <= 0) { /*C closed connection*/ shutdown (Csd, 2); close (Csd); Csd=-1; /*Tell A nothing more to hope for*/ shutdown (Asd, 2); close (Asd); Asd=-1; printf ("Closed connection : address: %s port=%d \n", inet_ntoa (sa.sin_addr),ntohs (sa.sin_port)); exit(0); #ifdef TESTING printf ("pid %d:quiting, C closed connection \n",getpid()); #endif } else { #ifdef ALLTESTING printf ("\nbuffer written to A is:#%s#=%d bytes\n", buffer, b); #endif #ifdef TESTING printf("\nWriting to A..."); #endif /*Write data to A*/ write (Asd, &buffer, b); #ifdef DEBUG printf ("C to A: #%s#\n", buffer); #endif #ifdef TESTING printf("Ok...\n"); #endif } } } } /*End of main*/ connectC(char *host,char *port) { /*Open C socket and connect to C host*/ if ((Csd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("Can't open C socket"); exit (-2); } sc.sin_port = htons ((u_short) atoi (port)); chost = gethostbyname (host); #ifdef TESTING printf ("\nC address : %s %d \n" , inet_ntoa (chost->h_addr), ntohs(sc.sin_port)); #endif sc.sin_family = AF_INET; memcpy (&sc.sin_addr, chost->h_addr, chost->h_length); if (connect (Csd,(struct sockaddr *) &sc, sizeof (sc)) < 0) { perror ("Can't connect to C"); exit (-3); } #ifdef TESTING else printf("Connected to C\n"); #endif cdown=0; } my_usleep(x) { struct timeval time; time.tv_sec= x/1000000; time.tv_usec=x%1000000; select(0, NULL, NULL, NULL, &time); } void childhdl () { wait (0); we_full--; #ifdef TESTING printf("\nInside childhandler, a child died\n"); #endif signal (SIGCHLD, childhdl); } newdest() { int c,ph; ph=0; bzero(buffer,sizeof(buffer)); c=read(rConfsd,buffer,sizeof(buffer)); if (c <= 0) { printf("Configuration port closed,shuting down\n"); if (Asd>0) shutdown (Asd,2); if (Csd>0) shutdown (Csd,2); shutdown (Confsd,2); close (Asd); close (Csd); close (Confsd); exit(5); } else buffer[c]='\0'; sscanf(buffer,"%s%s",desthost,destport); if (!strcmp(desthost,"help")) { strcpy(buffer,"\nJust type hostname and port, i.e. \"www.sun.com 80\"\n"); strcat(buffer,"or type \"exit\" to exit\n\n"); } else if (!strcmp(desthost,"exit")) { printf("Configuration port requested exit,shuting down\n"); if (Asd>0) shutdown (Asd,2); if (Csd>0) shutdown (Csd,2); shutdown (Confsd,2); close (Asd); close (Csd); close (Confsd); exit(5); } else sprintf(buffer,"\nDestination host: %s\nDestination port:%s\n", desthost,destport); strcat(buffer,"\nDestination > "); write(rConfsd,buffer,strlen(buffer)); }