/* Subject: general purpose telnet server. This is a telnet bouncer that some people have expressed interest in. It's uses are utility and privacy related. It should compile easily on most OS's striaght out of it's wrapper as such. Mark mark@cairo.anu.edu.au */ /* Name: ts2.c */ /* Author: Hal-9000, Xanadude, Richard Stevens, Avalon, Mark */ /* Distribution: Public */ /* Copyright: Held by the respective contributors */ /* Posted to USENET September '93 by Mark mark@cairo.anu.edu.au */ /* This file was telserv.c, part of the Telnet Server package v. 1.0, written by "Hal-9000". Much of that package was developed by Richard Stephens and his thanks go to "Xanadude" for providing him with that section. Performance fix by Darren Reed. */ /* Reworked to add concurrency, password checking and destination selection on the fly. - Mark 31st Aug 93 Compiled and tested on: HPUX 9.01 9000/700 series NeXTStep 3.1 NeXT 68040 OSx Pyramid 90x BSD universe SunOS 5.2 sun4c Ultrix 4.3 DEC RISC Linux 0.99.10 80486 To compile, type "cc -O -s ts2.c -o ts2". MY_PASSWORD and SERV_TCP_PORT are all that is required to be altered. */ #define MY_PASSWORD "bollox" #define SERV_TCP_PORT 9090 /* port I'll listen for connections on */ #include #include #include #include #include #include #include #include #include #include #include #include #define QLEN 5 char sbuf[2048], cbuf[2048]; extern int errno; extern char *sys_errlist[]; void reaper(); int main(); void telcli(); int main(argc, argv) int argc; char *argv[]; { int srv_fd, rem_fd, rem_len, opt = 1; struct sockaddr_in rem_addr, srv_addr; #if !defined(SVR4) && !defined(POSIX) && !defined(linux) && !defined(__386BSD__) && !defined(hpux) union wait status; #else int status; #endif /* !defined(SVR4) */ 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(SERV_TCP_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); close(1); close(2); #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); } switch(fork()) { case 0: /* child process */ close(srv_fd); /* close original socket */ telcli(rem_fd); /* process the request */ close(rem_fd); exit(0); break; default: close(rem_fd); /* parent process */ if (fork()) exit(0); /* let init worry about children */ break; case -1: fprintf(stderr, "\n\rfork: %s\n\r", sys_errlist[errno]); break; } } } 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]; bzero(gethost, 100); sprintf(string, "Password: "); write(source, string, strlen(string)); read(source, gethost, 100); gethost[(strlen(gethost)-2)] = '\0'; /* kludge alert - kill the \r\n */ if (strcmp(gethost, MY_PASSWORD) != 0) { sprintf(string, "Wrong password, got %s.\n", gethost); write(source, string, strlen(string)); close(source); exit(0); } do { found = 0; bzero(gethost,100); sprintf(string, "Host: "); write(source, string, strlen(string)); read(source, gethost, 100); gethost[(strlen(gethost)-2)] = '\0'; hp = gethostbyname(gethost); 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) */ sprintf(string, "Found address for %s\n", hp->h_name); write(source, string, strlen(string)); } 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; sprintf(string, "Port: "); write(source, string, strlen(string)); read(source, getport, 100); gethost[(strlen(getport)-2)] = '\0'; sa.sin_port = htons((unsigned) atoi(getport)); 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; } } sprintf(string, "Trying %s...\n", (char *) inet_ntoa(sa.sin_addr)); write(source, string, strlen(string)); if ((dest = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("telcli: socket"); exit(1); } connect(dest, (struct sockaddr *) &sa, sizeof(sa)); sprintf(string, "Connected to %s port %d...\n", inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); write(source, string, strlen(string)); #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); 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); if ((num==-1) && (errno != EWOULDBLOCK)) return; if (num>0) { shead += num; if (shead == stail) { shead = stail = sbuf; spos = 0; } if (!--nfd) continue; } } } }