/* * fwg.c - fakewingate v0.4 by ajax(ajax@mobis.com) and rsh * * accept connections on specified port (default port 23) and display * generic WinGate> prompt. Telnet to specified hostname and port number * and log everything to logfile (default stdout). * * Handles telnet negotiation and line buffers telnet sessions, which * are character buffered. * * compile: gcc -O2 -o fwg fwg.c */ #include #include #include #include #include #include #include #include #include #include #include #include extern char *optarg; extern int optind; /* * function declarations */ void signal_handler(int sig); void negotiate_telnet(int netfd, unsigned char *buf, unsigned int size); void appendbuf(unsigned char *dst, unsigned char *src, int size); void cleanup(int sig); /* * global variables */ int hflag=0,oflag=0,pflag=0,l,i,bv,listen_port=0,test,connection_start=1; int soc_client,s,user_fd,soc_len=sizeof(struct sockaddr_in); int dest_port=0, start_of_connection, telnet_negotiated=0; int debug=0; char *filename=NULL; unsigned char line[1024], enter_pressed = 0; int clear_line=0, on=1; FILE *outfile; int main(int argc, char *argv[]) { register int op; u_long timeout; fd_set rl; struct sockaddr_in serv_addr, client_addr; char *opop,host[60]; unsigned char rbuf[1024]; struct hostent *he; while ( (op = getopt(argc, argv, "o:p:h")) != EOF ) { switch (op) { case 'h': ++hflag; printf ("FakeWingate v0.02 (c) 1998 by ajax\n"); printf ("usage: %s [-o logfile] [-p port] [-h]\n",argv[0]); exit(0); break; case 'p': ++pflag; listen_port=atoi(optarg); fprintf(stderr,"[%s]: Using port %d\n",argv[0],listen_port); break; /* port */ case 'o': ++oflag; filename=optarg; if ((outfile = fopen(optarg, "a")) == NULL) { fprintf(stderr, "[%s]: error opening %s, using stdout\n", argv[0], optarg); outfile = stdout; } else { fprintf(stderr,"[%s]: Using output file: %s\n", argv[0],optarg); } break; /*outfile */ } } if (!filename) { fprintf(stderr,"[%s]: Using output file: stdout\n",argv[0]); outfile=stdout; } if (!pflag) { /* no output file specified, use stdout */ listen_port = 23; fprintf(stderr,"[%s]: Using port %d\n",argv[0],listen_port); } signal(SIGCHLD, signal_handler); signal(SIGINT, cleanup); signal(SIGTERM, cleanup); signal(SIGQUIT, cleanup); if((s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) { /* open tcp socket */ fprintf(stderr,"error opening socket.\n"); exit(1); } /* * Set the socket option for local address reuse. * If we do not set this option, further attempts to reuse this port * will fail until it times out. annoying. */ (void) setsockopt(s,SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); client_addr.sin_family=AF_INET; client_addr.sin_port=htons(listen_port); client_addr.sin_addr.s_addr=htonl(INADDR_ANY); if(bind(s,(struct sockaddr *)&client_addr,sizeof(client_addr)) == -1) { fprintf(stderr,"error bind() local prot addr.\n"); exit(1); } if(listen(s,5) == -1) { fprintf(stderr,"error setting backlog.\n"); exit(1); } for(;;) { if((soc_client=accept(s,NULL,&soc_len)) == -1) { fprintf(stderr,"error calling accept()\n"); exit(1); } if(fork()==0) { close(s); again: write(soc_client,"\nWinGate> ",10); bv=read(soc_client,rbuf,1024); rbuf[bv]='\0'; /* add null byte to end */ if (strstr(rbuf,"quit")) { shutdown(soc_client,2);close(s); exit(0); } sscanf(rbuf,"%s %d",host,&dest_port); if (dest_port==0) { dest_port = 23; } fprintf(outfile,"\n---[ host:%s, port:%d\n",host,dest_port); if((serv_addr.sin_addr.s_addr=inet_addr(host)) == -1) { if((he=gethostbyname(host)) == NULL) { write(soc_client,"error resolving hostname",24); goto again; } memcpy(&serv_addr.sin_addr.s_addr,he->h_addr, sizeof(serv_addr.sin_addr.s_addr)); } serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(dest_port); if((user_fd=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) { fprintf(stderr,"error allocating socket.\n"); goto again; } if(connect(user_fd,(struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) { write(soc_client,"invalid address\n",16); goto again; } // We dont need to display to caller what host and port they are going to // snprintf(rbuf,sizeof(rbuf),"\n---[ port: %d host: %s]\n\n",(port==0) ? 23 : port,host); // write(n,rbuf,strlen(rbuf)); FD_ZERO(&rl); start_of_connection = 1; telnet_negotiated = 0; /* reset this flag */ memset(line, '\0',1024); /* zero out buffer used by appendbuf() */ for(;;) { FD_SET(user_fd,&rl); FD_SET(soc_client,&rl); if(select((user_fd>soc_client) ? user_fd+1 : soc_client+1,&rl,NULL,NULL,NULL) == -1) { fprintf(stderr,"select() error\n"); exit(1); } if(FD_ISSET(soc_client,&rl)) { if((bv=read(soc_client,rbuf,1024)) <= 0) { write(soc_client,"\r\nConnection closed.\r\n",22); shutdown(user_fd,2); shutdown(soc_client,2); exit(1); } rbuf[bv]='\0'; if(debug) printf ("debug: bv=%d, rbuf=%s\n",bv,rbuf); /* * due to the fact that telnetd may be running on any port, * we should check all connections at the start_of_connection. */ if (start_of_connection) { negotiate_telnet(soc_client, rbuf, bv); start_of_connection = 0; /* reset this flag */ } /*if (strchr(rbuf,'^') { * write(soc_client,"Connection terminated.\n",25); * shutdown(user_fd,2); shutdown(soc_client,2); * exit(1); * } */ /* * log user input */ /* * If the telnet_negotiated flag is set, this means * the current connection we are in is a telnet session. * Each character needs to be buffered up to a ^M (0x0d) * and then logged after a ^M is recieved. Without this, * we would have each character logged on an individual line. */ if (telnet_negotiated) { if (clear_line) { memset(line,'\0',1024); clear_line=0; } appendbuf(line, rbuf, strlen(rbuf)); if (enter_pressed) { fprintf(outfile,"\n%s:%s",host,line); enter_pressed = 0; } } else { fprintf(outfile,"\n%s:%s",host,rbuf); } write(user_fd,rbuf,strlen(rbuf)); } if(FD_ISSET(user_fd,&rl)) { if((bv=read(user_fd,rbuf,1024)) <= 0) { write(soc_client,"\n\rConnection closed.\n",20); shutdown(user_fd,2); shutdown(soc_client,2); exit(1); } rbuf[bv]='\0'; // fprintf(outfile,"\nsoc_client:%s:%s",host,rbuf); write(soc_client,rbuf,strlen(rbuf)); } } } } fclose(outfile); exit(0); } void signal_handler(int sig) { while(waitpid(-1,NULL,WNOHANG) > 0) ; } void cleanup (int sig) { printf("Caught signal %d, exiting.\n",sig); shutdown(user_fd,2); shutdown(soc_client,2); close(user_fd); close(soc_client); exit(0); } void appendbuf(unsigned char *dst, unsigned char *src, int size) { while(*dst) *dst++; /* seek to end of string */ while(*src && *src!=0x0d && size--) *dst++ = *src++; if (*src==0x0d) { enter_pressed=1; clear_line=1; } } void negotiate_telnet (int netfd, unsigned char *buf, unsigned int size) { static unsigned char obuf [4]; /* tiny thing to build responses into */ register int x; register unsigned char y; register unsigned char * p; y = 0; p = buf; x = size; while (x > 0) { if (*p != 255) /* IAC? */ goto notiac; obuf[0] = 255; p++; x--; if ((*p == 251) || (*p == 252)) /* WILL or WONT */ y = 254; /* -> DONT */ if ((*p == 253) || (*p == 254)) /* DO or DONT */ y = 252; /* -> WONT */ if (y) { obuf[1] = y; p++; x--; obuf[2] = *p; /* copy actual option byte */ telnet_negotiated = 1; /* set the telnet_negotiation flag */ (void) write (netfd, obuf, 3); y = 0; } /* if y */ notiac: p++; x--; } /* while x */ } /* negotiate_telnet */