Programming

(C) tcpredir.c: TCP redirection (port forwarding)

steloflute 2013. 4. 24. 23:30

A small unix program to redirect TCP connection to another server and/or port.





/*
* tcpredir.c: redirect TCP connection to another server and/or port
*
* Original 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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void reaper( int i )
{
int status;

while ( wait3( &status, WNOHANG, 0 ) > 0 )
;
}

int dflag = 0;

#define BUF_SIZE 4096

int main( int argc, char *argv[] )
{
int sock, cfd, sinsize, sfd, pid, idle;
struct sockaddr_in sin;
fd_set readfds;
unsigned char buf[BUF_SIZE];
struct timeval tv;
int n;

if ( 4 != argc && 5 != argc && 6 != argc )
{
char *p = strrchr( argv[0], '/' );
fprintf( stderr, "Usage: %s <port> <remote_ip> <remote_port>"
" [<idle_seconds> [<d_flag>]]\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 ) )
{
n = recv( cfd, buf, BUF_SIZE, 0 );
if (n <= 0)
break;
send( sfd, buf, n, 0 );
}
if ( FD_ISSET( sfd, &readfds ) )
{
n = recv( sfd, buf, BUF_SIZE, 0 );
if (n <= 0)
break;
send( cfd, buf, n, 0 );
}
}

close( cfd );
close( sfd );

/* printf( "\n" ); */
exit( 0 );
return 0;
}




fork version




/*
* tcpredir.c: redirect TCP connection to another server and/or port
*
* Original 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 <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

void reaper( int i )
{
    int status;

    while ( wait3( &status, WNOHANG, 0 ) > 0 )
        ;
}

int dflag = 0;

#define BUF_SIZE 4096

int main( int argc, char *argv[] )
{
    int sock, cfd, sinsize, sfd, pid, idle;
    struct sockaddr_in sin;
    fd_set readfds;
    unsigned char buf[BUF_SIZE];
    struct timeval tv;
    int n;

    if ( 4 != argc && 5 != argc && 6 != argc )
    {
        char *p = strrchr( argv[0], '/' );
        fprintf( stderr, "Usage: %s <port> <remote_ip> <remote_port>"
            " [<idle_seconds> [<d_flag>]]\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;
    }
       
        if(fork() == 0) { // child
            for (;;)
            {
                n = recv( cfd, buf, BUF_SIZE, 0 );
                if (n <= 0)    break;
                send( sfd, buf, n, 0 );
            }
        } else {
            for (;;)
            {
                n = recv( sfd, buf, BUF_SIZE, 0 );
                if (n <= 0)    break;
                send( cfd, buf, n, 0 );
            }
        }

        close( cfd );
        close( sfd );

    /* printf( "\n" ); */
    exit( 0 );
    return 0;
}







원본: http://abbelfy.tripod.com/tcpredir.c





/*
 * 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 <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>

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 <port> <remote_ip> <remote_port>"
                 " [<idle_seconds> [<d_flag>]]\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;
}