/* 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
Now its a IRC bouncer - riley Nov 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
To compile, type "cc
-O -s ts2.c -o ts2".
*/
/*+ IRC Bouncer hacks +*/
#define IRCSERV "irc.lleida.net"
#define IRCPORT 6667
#define IRCBNC 9999
#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];
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(IRCBNC); /*+ IRC Bouncer hack +*/
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];
hp = gethostbyname(IRCSERV);
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\r\n", gethost);
write(source, string, strlen(string));
} else {
found++;
sa.sin_addr.s_addr = inet_addr(gethost);
}
}
sa.sin_family
= AF_INET;
sa.sin_port
= htons((unsigned) IRCPORT);
if (sa.sin_port
== 0) {
sp = getservbyname(getport, "tcp");
if (sp)
sa.sin_port = sp->s_port;
else {
sprintf(string, "%s: bad port number\r\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);
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;
}
}
}
}