/* * tcpredir.c: redirect TCP connection to another server and/or port * * Author: abbelf@usa.net * * $Id: tcpredir.c,v 1.3 2000/12/01 00:15:28 hanhua Exp $ */ /* * Compilation: * cc -o tcpredir tcpredir.c [-lsocket -lnsl] * * Usage: * tcpredir 4000 202.112.26.39 2323 * To redirect connection accepted on port 4000 to 202.112.26.39:2323 * tcpredir 4000 202.112.26.39 2323 1800 * To redirect connection and cut off the connection in half an hour * tcpredir 4000 202.112.26.39 2323 0 2 * To redirect connection, monitor mode 2, without cutting off connection * * Comments: * Monitor mode including 1(hex mode) 2(c string mode). * This program goes into background automatically by folking a sub-process. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void reaper( int i ) { int status; while ( wait3( &status, WNOHANG, 0 ) > 0 ) ; } int dflag = 0; void debug( unsigned char ch, int n ) { static char buf[2][82]; static int p[2] = { 0, 0 }; if ( dflag == 0 ) return; if ( dflag == 1 ) { printf("%c%02X", n ? '>' : '<', ch ); return; } if ( dflag == 2 ) { switch( ch ) { case '\r': buf[n][p[n]++] = '\\'; buf[n][p[n]++] = 'r'; break; case '\n': buf[n][p[n]++] = '\\'; buf[n][p[n]++] = 'n'; buf[n][p[n]] = '\0'; p[n] = 78; break; case '\t': buf[n][p[n]++] = '\\'; buf[n][p[n]++] = 't'; break; case '\\': buf[n][p[n]++] = '\\'; buf[n][p[n]++] = '\\'; break; default: if ( ch >= 0x20 && ch < 0x7f ) { buf[n][p[n]++] = ch; } else { buf[n][p[n]++] = '\\'; buf[n][p[n]++] = 'x'; buf[n][p[n]++] = ch/16 >= 10 ? ch/16 + 'A' - 10 : ch/16 + '0'; buf[n][p[n]++] = ch%16 >= 10 ? ch%16 + 'A' - 10 : ch%16 + '0'; } } if ( p[n] >= 76 ) { buf[n][p[n]] = '\0'; printf( "%c%s\n", n ? '>' : '<', buf[n] ); p[n] = 0; } } } int main( int argc, char *argv[] ) { int sock, cfd, sinsize, sfd, pid, idle; struct sockaddr_in sin; fd_set readfds; unsigned char ch; struct timeval tv; if ( 4 != argc && 5 != argc && 6 != argc ) { char *p = strrchr( argv[0], '/' ); fprintf( stderr, "Usage: %s " " [ []]\n", p ? p+1 : argv[0] ); return 0; } if ( 6 == argc ) dflag = atoi( argv[5] ); if ( 5 == argc || 6 == argc ) idle = atoi( argv[4] ); else idle = 0; if ( ( sock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror( "socket" ); return -1; } sin.sin_family = AF_INET; sin.sin_port = htons( atoi( argv[1] ) ); sin.sin_addr.s_addr = INADDR_ANY; if ( bind( sock, (struct sockaddr *) &sin, sizeof(sin) ) < 0 ) { perror( "bind" ); return -1; } sinsize = sizeof(sin); if ( getsockname( sock, (struct sockaddr *) & sin, &sinsize ) == -1 ) { perror( "getsockname" ); return -1; } if ( listen( sock, 5 ) == -1 ) { perror( "listen" ); return -1; } if ( ( pid = fork() ) ) { printf( "%d\n", pid ); return 0; } setpgid( 0, 0 ); signal( SIGHUP, SIG_IGN ); signal( SIGINT, SIG_IGN ); signal( SIGQUIT, SIG_IGN ); signal( SIGALRM, SIG_IGN ); signal( SIGURG, SIG_IGN ); signal( SIGTSTP, SIG_IGN ); signal( SIGTTIN, SIG_IGN ); signal( SIGTTOU, SIG_IGN ); for(;;) { signal( SIGCHLD, reaper ); sinsize = sizeof(sin); sfd = accept( sock, (struct sockaddr *)&sin, &sinsize ); if ( sfd == -1 ) continue; pid = fork(); if ( 0 == pid ) break; close( sfd ); } close( sock ); sin.sin_family = PF_INET; sin.sin_addr.s_addr = inet_addr( argv[2] ); sin.sin_port = htons( atoi( argv[3] ) ); cfd = socket( sin.sin_family, SOCK_STREAM, 0 ); if ( cfd < 0 ) { char *errmsg = "Socket error\n"; send( sfd, errmsg, strlen( errmsg ), 0 ); return -1; } if ( connect( cfd, (struct sockaddr *) &sin, sizeof sin) ) { char *errmsg = "Connecting failed\n"; send( sfd, errmsg, strlen( errmsg ), 0 ); return -1; } for (;;) { tv.tv_sec = idle; tv.tv_usec = 0; FD_ZERO( &readfds ); FD_SET( sfd, &readfds ); FD_SET( cfd, &readfds ); if ( select( sfd>cfd ? sfd+1 : cfd+1, &readfds, NULL, NULL, idle > 0 ? &tv : NULL ) <= 0 ) break; if ( FD_ISSET( cfd, &readfds ) ) { if ( 1 != recv( cfd, &ch, 1, 0 ) ) break; send( sfd, &ch, 1, 0 ); debug( ch, 1 ); } if ( FD_ISSET( sfd, &readfds ) ) { if ( 1 != recv( sfd, &ch, 1, 0 ) ) break; send( cfd, &ch, 1, 0 ); debug( ch, 0 ); } } close( cfd ); close( sfd ); /* printf( "\n" ); */ exit( 0 ); return 0; }