/* Port forwarder, some code ripped I don't remember from where, drop me an
 * e-mail if you do.
 * dreyer - luna@aditel.org 2001 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
 
#define    QLEN           5
 
char sbuf[2048], cbuf[2048];
char *SERVER;
int SERV_PORT;
extern int errno;
void reaper();
int main();
void telcli();
 
int main(argc, argv)
int argc;
char *argv[];
{
    int srv_fd, rem_fd, rem_len, opt = 1,LOCAL_PORT;
    struct sockaddr_in rem_addr, srv_addr;
      
    if (argc!=4) { printf("Uso: %s localport dest port\n",argv[0]);exit(-1); }
    LOCAL_PORT=atoi(argv[1]);
    SERVER=argv[2];
    SERV_PORT=atoi(argv[3]);
    bzero((char *) &rem_addr, sizeof(rem_addr));
    bzero((char *) &srv_addr, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    srv_addr.sin_port = htons(LOCAL_PORT);
    srv_fd = socket(PF_INET, SOCK_STREAM, 0);
    if (bind(srv_fd, (struct sockaddr *) &srv_addr, sizeof(srv_addr)) == -1) {
        perror("bind");
        exit(-1);
    }
    listen(srv_fd, QLEN);
    close(0); 
#ifdef TIOCNOTTY
    if ((rem_fd = open("/dev/tty", O_RDWR)) >= 0) {
        ioctl(rem_fd, TIOCNOTTY, (char *)0);
        close(rem_fd);
    }
#endif
    //if (fork()) exit(0);

    while (1) {
    rem_len = sizeof(rem_addr);
        rem_fd=accept(srv_fd, (struct sockaddr *) &rem_addr, &rem_len);
        if (rem_fd < 0) {
            if (errno == EINTR) continue;
            exit(-1);
        }
            close(srv_fd);                  /* close original socket */
            telcli(rem_fd);                 /* process the request */
            close(rem_fd);
            exit(0);
    }
}
 
void telcli(source)
int source;
{
    int dest;
    int found;
    struct sockaddr_in sa;
    struct hostent *hp;
    struct servent *sp;
    char gethost[100];
    char getport[100];
    char string[100];
 
    //write(source, string, strlen(string));
    do {
		found = 0;
		bzero(gethost,100);
        hp = gethostbyname(SERVER);
        if (hp) {
            found++;
#if !defined(h_addr)        /* In 4.3, this is a #define */
#if defined(hpux) || defined(NeXT) || defined(ultrix) || defined(POSIX)
            memcpy((caddr_t)&sa.sin_addr, hp->h_addr_list[0], hp->h_length);
#else
            bcopy(hp->h_addr_list[0], &sa.sin_addr, hp->h_length);
#endif
#else /* defined(h_addr) */
#if defined(hpux) || defined(NeXT) || defined(ultrix) || defined(POSIX)
            memcpy((caddr_t)&sa.sin_addr, hp->h_addr, hp->h_length);
#else
            bcopy(hp->h_addr, &sa.sin_addr, hp->h_length);
#endif
#endif /* defined(h_addr) */
        } else {
            if (inet_addr(gethost) == -1) {
                found = 0;
                sprintf(string, "Didnt find address for %s\n", gethost);
                write(source, string, strlen(string));
            } else {
                found++;
                sa.sin_addr.s_addr = inet_addr(gethost);
            }
        }
    } while (!found);
    sa.sin_family = AF_INET;
    sa.sin_port = htons(SERV_PORT);
    if (sa.sin_port == 0) {
        sp = getservbyname(getport, "tcp");
        if (sp)
            sa.sin_port = sp->s_port;
        else {
            sprintf(string, "%s: bad port number\n", getport);
            write(source, string, strlen(string));
            return;
        }
    }
    if ((dest = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        perror("telcli: socket");
        exit(1);
    }
    connect(dest, (struct sockaddr *) &sa, sizeof(sa));
#ifdef FNDELAY
    fcntl(source,F_SETFL,fcntl(source,F_GETFL,0)|FNDELAY);
    fcntl(dest,F_SETFL,fcntl(dest,F_GETFL,0)|FNDELAY);
#else
    fcntl(source,F_SETFL,O_NDELAY);
    fcntl(dest,F_SETFL,O_NDELAY);
#endif
    communicate(dest,source);
    close(dest);
    exit(0);
}
 
communicate(sfd,cfd)    {
    char *chead, *ctail, *shead, *stail;
    int num, nfd, spos, cpos;
    extern int errno;
    fd_set rd, wr;
 
    chead = ctail = cbuf;
    cpos = 0;
    shead = stail = sbuf;
    spos = 0;
    while (1) {
        FD_ZERO(&rd);
        FD_ZERO(&wr);
        if (spos < sizeof(sbuf)-1) FD_SET(sfd, &rd);
        if (ctail > chead) FD_SET(sfd, &wr);
        if (cpos < sizeof(cbuf)-1) FD_SET(cfd, &rd);
        if (stail > shead) FD_SET(cfd, &wr);
        nfd = select(256, &rd, &wr, 0, 0);
        if (nfd <= 0) continue;
        if (FD_ISSET(sfd, &rd)) {
            num=read(sfd,stail,sizeof(sbuf)-spos);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num==0) return;
            if (num>0) {
                spos += num;
                stail += num;
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(cfd, &rd)) {
            num=read(cfd,ctail,sizeof(cbuf)-cpos);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num==0) return;
            if (num>0) {
                cpos += num;
                ctail += num;
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(sfd, &wr)) {
            num=write(sfd,chead,ctail-chead);
            write(1,"\033[0;32m",7);
            write(1,chead,ctail-chead);
            write(1,"\033[0m",4);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num>0) {
                chead += num;
                if (chead == ctail) {
                    chead = ctail = cbuf;
                    cpos = 0;
                }
                if (!--nfd) continue;
            }
        }
        if (FD_ISSET(cfd, &wr)) {
            num=write(cfd,shead,stail-shead);
            write(1,shead,stail-shead);
            if ((num==-1) && (errno != EWOULDBLOCK)) return;
            if (num>0) {
                shead += num;
                if (shead == stail) {
                    shead = stail = sbuf;
                    spos = 0;
                }
                if (!--nfd) continue;
            }
        }
    }
}
 

