/* * (C) 1995 Todd Vierling * ----------------------------------------------------------------------- * Rewrite : scz * Version : 1.12 2005-02-24 12:55 * Compile : For x86/Linux RedHat_8 2.4.18-14 * : gcc -DLinux -static -Wall -pipe -O3 -s -o datapipe datapipe.c * : * : For x86/FreeBSD 4.5-RELEASE * : gcc -DFreeBSD -static -Wall -pipe -O3 -s -o datapipe datapipe.c * : * : For SPARC/Solaris 8 * : gcc -DSparc -Wall -pipe -O3 -s -o datapipe datapipe.c -lsocket -lnsl * : * : For AIX 4.3.3.0 * : gcc -DAix -Wall -pipe -O3 -s -o datapipe datapipe.c * : * : (strip datapipe or gcc -s) * : mcs -d datapipe (only for Solaris) * : * : If you want to debug this code, compiling it with "-DDEBUG -g" without "-O3" * : * Create : 1995 * Modify : 2005-02-24 12:55 * ----------------------------------------------------------------------- * The only thing they can't take from us are our minds. !H */ /* * 由于已经daemon化,很多perror()实际上无意义,留着只是备忘。还有一些看上 * 去比较怪异的代码,因为我不是只写一个程序,其它想法需要共享代码片段。 * * 与1.00版的区别在于试图支持FTP数据流,处理PORT命令、PASV响应,支持FTP级 * 联。由于对FTP的支持影响效率,如非绝对必要,不要在命令行上指定-f。 * * 1.12版重新整理了一下代码风格。 */ /************************************************************************ * * * Head File * * * ************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef Linux #include #endif #include #include #ifdef FreeBSD #include #include #endif #include #include #include #include /************************************************************************ * * * Macro * * * ************************************************************************/ #define VERSION "1.12 2005-02-24 12:55" #if defined(Sparc) || defined(Solaris) #define INADDR_NONE 0xFFFFFFFF #endif #ifdef Linux #define POLLRDNORM 0x040 #endif typedef void Sigfunc ( int ); /************************************************************************ * * * Function Prototype * * * ************************************************************************/ static int Accept ( int s, struct sockaddr *addr, size_t *addrlen ); static void Atexit ( void ( *func ) ( void ) ); static void Bind ( int s, struct sockaddr *addr, size_t addrlen ); static void daemon_init ( char *workdir, mode_t mask ); static void doFtpRelay ( int connectSocket, int remoteSocket ); static void doTcpRelay ( int connectSocket, int remoteSocket ); static int Dup2 ( int oldfd, int newfd ); static pid_t Fork ( void ); static void Getsockname ( int s, struct sockaddr *name, size_t *namelen ); static void init_signal ( void ); static int initTcpServer ( unsigned short int localPort ); static void Listen ( int s, int backlog ); static void on_terminate ( int signo ); static Sigfunc * PrivateSignal ( int signo, Sigfunc *func ); static unsigned int resolveHost ( char *host ); static Sigfunc * Signal ( int signo, Sigfunc *func ); static int Socket ( int family, int type, int protocol ); static int tcp_connect ( unsigned int ip, unsigned short int port, unsigned int timeout ); static void tcprelay ( unsigned int remoteHost, unsigned short int remotePort ); static void terminate ( void ); static void usage ( char *arg ); static ssize_t writen ( int fd, void *vptr, size_t n ); /************************************************************************ * * * Static Global Var * * * ************************************************************************/ static int acceptSocket = -1; static int connectSocket = -1; static int remoteSocket = -1; static unsigned int supportftp = 0; /************************************************************************/ static int Accept ( int s, struct sockaddr *addr, size_t *addrlen ) { int n; n = accept( s, addr, addrlen ); if ( -1 == n ) { perror( "accept error" ); exit( EXIT_FAILURE ); } return( n ); } /* end of Accept */ static void Atexit ( void ( * func ) ( void ) ) { if ( 0 != atexit( func ) ) { perror( "atexit error" ); exit( EXIT_FAILURE ); } return; } /* end of Atexit */ static void Bind ( int s, struct sockaddr *addr, size_t addrlen ) { if ( -1 == bind( s, ( const struct sockaddr * )addr, addrlen ) ) { perror( "bind error" ); exit( EXIT_FAILURE ); } return; } /* end of Bind */ static void daemon_init ( char *workdir, mode_t mask ) { int i, j; chdir( "/tmp" ); if ( 0 != Fork() ) { exit( EXIT_SUCCESS ); } setsid(); Signal( SIGHUP, SIG_IGN ); if ( 0 != Fork() ) { exit( EXIT_SUCCESS ); } chdir( workdir ); umask( mask ); if ( -1 == ( j = open( "/dev/null", O_RDWR ) ) ) { perror( "open error" ); exit( EXIT_FAILURE ); } Dup2( j, 0 ); Dup2( j, 1 ); Dup2( j, 2 ); j = getdtablesize(); for ( i = 3; i < j; i++ ) { close( i ); } return; } /* end of daemon_init */ static void doFtpRelay ( int connectSocket, int remoteSocket ) { unsigned char buf[1025]; unsigned int num[6]; struct pollfd fds[4]; int c; struct sockaddr_in localAddr0, localAddr1, localAddr; size_t localAddrLen0, localAddrLen1, localAddrLen; unsigned int portRemoteIp, pasvRemoteIp, Ip; unsigned short int portRemotePort, portLocalPort, pasvRemotePort, pasvLocalPort, Port; int portAcceptSocket, portConnectSocket, portRemoteSocket; int pasvAcceptSocket, pasvConnectSocket, pasvRemoteSocket; portAcceptSocket = -1; portConnectSocket = -1; portRemoteSocket = -1; pasvAcceptSocket = -1; pasvConnectSocket = -1; pasvRemoteSocket = -1; portRemoteIp = 0; pasvRemoteIp = 0; portRemotePort = 0; portLocalPort = 0; pasvRemotePort = 0; pasvLocalPort = 0; localAddrLen0 = sizeof( localAddr0 ); localAddrLen1 = sizeof( localAddr1 ); memset( &localAddr0, 0, localAddrLen0 ); memset( &localAddr1, 0, localAddrLen1 ); Getsockname( connectSocket, ( struct sockaddr * )&localAddr0, &localAddrLen0 ); Getsockname( remoteSocket, ( struct sockaddr * )&localAddr1, &localAddrLen1 ); for ( c = 0; c < 4; c++ ) { fds[c].fd = -1; fds[c].events = POLLRDNORM; } fds[0].fd = connectSocket; fds[1].fd = remoteSocket; for ( ; ; ) { c = poll( fds, 4, -1 ); if ( c < 0 ) { perror( "poll error" ); goto doFtpRelay_exit; } else if ( c == 0 ) { fprintf( stderr, "poll() failed for timeout.\n" ); goto doFtpRelay_exit; } if ( fds[0].revents & ( POLLRDNORM | POLLERR ) ) { c = read( connectSocket, buf, sizeof( buf ) - 1 ); if ( c < 0 ) { goto doFtpRelay_exit; } else if ( 0 == c ) { goto doFtpRelay_exit; } if ( 0 == strncasecmp( buf, "PORT ", 5 ) ) { buf[c] = '\0'; sscanf( buf + 5, "%u,%u,%u,%u,%u,%u", num, num + 1, num + 2, num + 3, num + 4, num + 5 ); portRemoteIp = htonl( ( num[0] << 24 ) + ( num[1] << 16 ) + ( num[2] << 8 ) + num[3] ); portRemotePort = htons( num[4] * 256 + num[5] ); portAcceptSocket = initTcpServer( 0 ); fds[2].fd = portAcceptSocket; localAddrLen = sizeof( localAddr ); memset( &localAddr, 0, localAddrLen ); Getsockname( portAcceptSocket, ( struct sockaddr * )&localAddr, &localAddrLen ); portLocalPort = localAddr.sin_port; Ip = ntohl( localAddr1.sin_addr.s_addr ); Port = ntohs( portLocalPort ); num[0] = ( Ip / 0x1000000 ) % 0x100; num[1] = ( Ip / 0x10000 ) % 0x100; num[2] = ( Ip / 0x100 ) % 0x100; num[3] = ( Ip / 0x1 ) % 0x100; num[4] = ( Port / 0x100 ) % 0x100; num[5] = ( Port / 0x1 ) % 0x100; sprintf( buf, "PORT %u,%u,%u,%u,%u,%u\r\n", num[0], num[1], num[2], num[3], num[4], num[5] ); c = strlen( buf ); } if ( writen( remoteSocket, buf, c ) < 0 ) { goto doFtpRelay_exit; } } if ( fds[1].revents & ( POLLRDNORM | POLLERR ) ) { c = read( remoteSocket, buf, sizeof( buf ) - 1 ); if ( c < 0 ) { goto doFtpRelay_exit; } else if ( 0 == c ) { goto doFtpRelay_exit; } if ( 0 == strncasecmp( buf, "227 Entering Passive Mode (", 27 ) ) { buf[c] = '\0'; sscanf( buf + 27, "%u,%u,%u,%u,%u,%u", num, num + 1, num + 2, num + 3, num + 4, num + 5 ); pasvRemoteIp = htonl( ( num[0] << 24 ) + ( num[1] << 16 ) + ( num[2] << 8 ) + num[3] ); pasvRemotePort = htons( num[4] * 256 + num[5] ); pasvAcceptSocket = initTcpServer( 0 ); fds[3].fd = pasvAcceptSocket; localAddrLen = sizeof( localAddr ); memset( &localAddr, 0, localAddrLen ); Getsockname( pasvAcceptSocket, ( struct sockaddr * )&localAddr, &localAddrLen ); pasvLocalPort = localAddr.sin_port; Ip = ntohl( localAddr0.sin_addr.s_addr ); Port = ntohs( pasvLocalPort ); num[0] = ( Ip / 0x1000000 ) % 0x100; num[1] = ( Ip / 0x10000 ) % 0x100; num[2] = ( Ip / 0x100 ) % 0x100; num[3] = ( Ip / 0x1 ) % 0x100; num[4] = ( Port / 0x100 ) % 0x100; num[5] = ( Port / 0x1 ) % 0x100; sprintf ( buf, "227 Entering Passive Mode (%u,%u,%u,%u,%u,%u)\r\n", num[0], num[1], num[2], num[3], num[4], num[5] ); c = strlen( buf ); } if ( writen( connectSocket, buf, c ) < 0 ) { goto doFtpRelay_exit; } } if ( fds[2].revents & ( POLLRDNORM | POLLERR ) ) { localAddrLen = sizeof( localAddr ); memset( &localAddr, 0, localAddrLen ); portConnectSocket = Accept( portAcceptSocket, ( struct sockaddr * )&localAddr, &localAddrLen ); close( portAcceptSocket ); portAcceptSocket = -1; fds[2].fd = -1; portRemoteSocket = tcp_connect( portRemoteIp, portRemotePort, 75 ); if ( portRemoteSocket >= 0 ) { doTcpRelay( portConnectSocket, portRemoteSocket ); shutdown( portRemoteSocket, SHUT_RDWR ); close( portRemoteSocket ); portRemoteSocket = -1; } shutdown( portConnectSocket, SHUT_RDWR ); close( portConnectSocket ); portConnectSocket = -1; } if ( fds[3].revents & ( POLLRDNORM | POLLERR ) ) { localAddrLen = sizeof( localAddr ); memset( &localAddr, 0, localAddrLen ); pasvConnectSocket = Accept( pasvAcceptSocket, ( struct sockaddr * )&localAddr, &localAddrLen ); close( pasvAcceptSocket ); pasvAcceptSocket = -1; fds[3].fd = -1; pasvRemoteSocket = tcp_connect( pasvRemoteIp, pasvRemotePort, 75 ); if ( pasvRemoteSocket >= 0 ) { doTcpRelay( pasvConnectSocket, pasvRemoteSocket ); shutdown( pasvRemoteSocket, SHUT_RDWR ); close( pasvRemoteSocket ); pasvRemoteSocket = -1; } shutdown( pasvConnectSocket, SHUT_RDWR ); close( pasvConnectSocket ); pasvConnectSocket = -1; } } /* end of for */ doFtpRelay_exit: if ( -1 != portAcceptSocket ) { close( portAcceptSocket ); portAcceptSocket = -1; } if ( -1 != portConnectSocket ) { close( portConnectSocket ); portConnectSocket = -1; } if ( -1 != portRemoteSocket ) { close( portRemoteSocket ); portRemoteSocket = -1; } if ( -1 != pasvAcceptSocket ) { close( pasvAcceptSocket ); pasvAcceptSocket = -1; } if ( -1 != pasvConnectSocket ) { close( pasvConnectSocket ); pasvConnectSocket = -1; } if ( -1 != pasvRemoteSocket ) { close( pasvRemoteSocket ); pasvRemoteSocket = -1; } return; } /* end of doFtpRelay */ static void doTcpRelay ( int connectSocket, int remoteSocket ) { unsigned char buf[1024]; struct pollfd fds[2]; int c; fds[0].fd = connectSocket; fds[0].events = POLLRDNORM; fds[1].fd = remoteSocket; fds[1].events = POLLRDNORM; for ( ; ; ) { c = poll( fds, 2, -1 ); if ( c < 0 ) { perror( "poll error" ); goto doTcpRelay_exit; } else if ( 0 == c ) { fprintf( stderr, "poll() failed for timeout\n" ); goto doTcpRelay_exit; } if ( fds[0].revents & ( POLLRDNORM | POLLERR ) ) { c = read( connectSocket, buf, sizeof( buf ) ); if ( c < 0 ) { goto doTcpRelay_exit; } else if ( 0 == c ) { goto doTcpRelay_exit; } if ( writen( remoteSocket, buf, c ) < 0 ) { goto doTcpRelay_exit; } } if ( fds[1].revents & ( POLLRDNORM | POLLERR ) ) { c = read( remoteSocket, buf, sizeof( buf ) ); if ( c < 0 ) { goto doTcpRelay_exit; } else if ( 0 == c ) { goto doTcpRelay_exit; } if ( writen( connectSocket, buf, c ) < 0 ) { goto doTcpRelay_exit; } } } /* end of for */ doTcpRelay_exit: return; } /* end of doTcpRelay */ static int Dup2 ( int oldfd, int newfd ) { int fd; fd = dup2( oldfd, newfd ); if ( -1 == fd ) { perror( "dup2 error" ); exit( EXIT_FAILURE ); } return( fd ); } /* end of Dup2 */ static pid_t Fork ( void ) { pid_t pid; pid = fork(); if ( -1 == pid ) { perror( "fork error" ); exit( EXIT_FAILURE ); } return( pid ); } /* end of Fork */ static void Getsockname ( int s, struct sockaddr *name, size_t *namelen ) { if ( -1 == getsockname( s, name, namelen ) ) { perror( "getsockname error" ); exit( EXIT_FAILURE ); } return; } /* end of Getsockname */ static void init_signal ( void ) { unsigned int i; Atexit( terminate ); for ( i = 1; i < 9; i++ ) { Signal( i, on_terminate ); } Signal( SIGTERM, on_terminate ); Signal( SIGALRM, on_terminate ); return; } /* end of init_signal */ static int initTcpServer ( unsigned short int localPort ) { struct sockaddr_in sin; int i; int acceptSocket; acceptSocket = Socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); i = 1; if ( -1 == setsockopt( acceptSocket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) ) ) { perror( "setsockopt( SO_REUSEADDR ) error" ); exit( EXIT_FAILURE ); } memset( &sin, 0, sizeof( sin ) ); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = localPort; Bind( acceptSocket, ( struct sockaddr * )&sin, sizeof( sin ) ); Listen( acceptSocket, 256 ); return( acceptSocket ); } /* end of initTcpServer */ static void Listen( int s, int backlog ) { if ( -1 == listen( s, backlog ) ) { perror( "listen error" ); exit( EXIT_FAILURE ); } return; } /* end of Listen */ static void on_terminate ( int signo ) { /* * 演示用,不推荐在信号句柄中使用fprintf() */ fprintf( stderr, "\nsigno = %d\n", signo ); exit( EXIT_SUCCESS ); } /* end of on_terminate */ static Sigfunc * PrivateSignal ( int signo, Sigfunc *func ) { struct sigaction act, oact; act.sa_handler = func; sigemptyset( &act.sa_mask ); act.sa_flags = 0; if ( signo == SIGALRM ) { #ifdef SA_INTERRUPT /* * SunOS 4.x */ act.sa_flags |= SA_INTERRUPT; #endif } else { #ifdef SA_RESTART /* * SVR4, 4.4BSD */ act.sa_flags |= SA_RESTART; #endif } if ( sigaction( signo, &act, &oact ) < 0 ) { return( SIG_ERR ); } return( oact.sa_handler ); } /* end of PrivateSignal */ static unsigned int resolveHost ( char *host ) { struct hostent *he; unsigned int ip; if ( ( he = gethostbyname( host ) ) == NULL ) { ip = inet_addr( host ); if ( INADDR_NONE == ip ) { fprintf( stderr, "Unknown host %s\n", host ); exit( EXIT_FAILURE ); } } else { memcpy( &ip, he->h_addr_list[0], sizeof( unsigned int ) ); } return( ip ); } /* end of resolveHost */ static Sigfunc * Signal ( int signo, Sigfunc *func ) { Sigfunc *sigfunc; if ( ( sigfunc = PrivateSignal( signo, func ) ) == SIG_ERR ) { perror( "signal" ); exit( EXIT_FAILURE ); } return( sigfunc ); } /* end of Signal */ static int Socket ( int family, int type, int protocol ) { int n; if ( ( n = socket( family, type, protocol ) ) < 0 ) { perror( "socket error" ); exit( EXIT_FAILURE ); } return( n ); } /* end of Socket */ static int tcp_connect ( unsigned int ip, unsigned short int port, unsigned int timeout ) { struct sockaddr_in sin; int s, flags, error_value, n; fd_set rset, wset; struct timeval tv; size_t error_value_len; memset( &sin, 0, sizeof( sin ) ); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ip; sin.sin_port = port; error_value = 0; error_value_len = sizeof( error_value ); if ( ( s = socket( PF_INET, SOCK_STREAM, 0 ) ) < 0 ) { perror( "socket error" ); return( -1 ); } if ( ( flags = fcntl( s, F_GETFL, 0 ) ) < 0 ) { perror( "fcntl( F_GETFL ) error" ); goto tcp_connect_1; } if ( fcntl( s, F_SETFL, flags | O_NONBLOCK ) < 0 ) { perror( "fcntl( F_SETFL ) error" ); goto tcp_connect_1; } if ( ( n = connect( s, ( struct sockaddr * )&sin, sizeof( sin ) ) ) < 0 ) { if ( errno != EINPROGRESS ) { /* * connect error: Connection refused * * perror( "connect error" ); */ goto tcp_connect_1; } } if ( n == 0 ) { goto tcp_connect_0; } FD_ZERO( &rset ); FD_SET( s, &rset ); wset = rset; tv.tv_sec = timeout; tv.tv_usec = 0; n = select( s + 1, &rset, &wset, NULL, timeout ? &tv : NULL ); if ( n < 0 ) { perror( "select error" ); goto tcp_connect_1; } else if ( 0 == n ) { /* * fprintf( stderr, "select returned with timeout.\n" ); */ goto tcp_connect_1; } else if ( FD_ISSET( s, &rset ) || FD_ISSET( s, &wset ) ) { if ( getsockopt( s, SOL_SOCKET, SO_ERROR, &error_value, &error_value_len ) < 0 ) { goto tcp_connect_1; } } else { fprintf( stderr, "some error occur in tcp_connect()\n" ); goto tcp_connect_1; } tcp_connect_0: if ( fcntl( s, F_SETFL, flags ) < 0 ) { perror( "fcntl( F_SETFL ) error" ); goto tcp_connect_1; } if ( 0 != error_value ) { goto tcp_connect_1; } n = 1; setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, &n, sizeof( n ) ); return( s ); tcp_connect_1: close( s ); return( -1 ); } /* end of tcp_connect */ static void tcprelay ( unsigned int remoteHost, unsigned short int remotePort ) { struct sockaddr_in clientAddr; size_t clientAddrLen; pid_t pid; for ( ; ; ) { clientAddrLen = sizeof( clientAddr ); memset( &clientAddr, 0, clientAddrLen ); connectSocket = Accept ( acceptSocket, ( struct sockaddr * )&clientAddr, &clientAddrLen ); pid = Fork(); if ( 0 == pid ) { close( acceptSocket ); acceptSocket = -1; pid = Fork(); if ( 0 == pid ) { if ( ( remoteSocket = tcp_connect( remoteHost, remotePort, 75 ) ) >= 0 ) { if ( 0 == supportftp ) { doTcpRelay( connectSocket, remoteSocket ); } else { doFtpRelay( connectSocket, remoteSocket ); } shutdown( remoteSocket, SHUT_RDWR ); close( remoteSocket ); remoteSocket = -1; shutdown( connectSocket, SHUT_RDWR ); } } close( connectSocket ); connectSocket = -1; exit( EXIT_SUCCESS ); } else { close( connectSocket ); connectSocket = -1; if ( pid != waitpid( pid, NULL, 0 ) ) { perror( "waitpid error" ); } } } /* end of for */ return; } /* end of tcprelay */ static void terminate ( void ) { if ( -1 != remoteSocket ) { close( remoteSocket ); remoteSocket = -1; } if ( -1 != connectSocket ) { close( connectSocket ); connectSocket = -1; } if ( -1 != acceptSocket ) { close( acceptSocket ); acceptSocket = -1; } return; } /* end of terminate */ static void usage ( char *arg ) { fprintf ( stderr, "Usage: %s [-h] [-v] [-d] [-f] [-l localPort] [-x remoteHost] [-y remotePort]\n", arg ); exit( EXIT_FAILURE ); } /* end of usage */ static ssize_t writen ( int fd, void *vptr, size_t n ) { ssize_t nwrite; size_t nleft; unsigned char *ptr = vptr; nleft = n; while ( nleft > 0 ) { if ( ( nwrite = write( fd, ptr, nleft ) ) <= 0 ) { if ( EINTR == errno || EAGAIN == errno ) { /* * call write() again */ nwrite = 0; } else { /* * error */ return( -1 ); } } nleft -= nwrite; ptr += nwrite; } /* end of while */ return( n ); } /* end of writen */ int main ( int argc, char * argv[] ) { int c; struct rlimit res; unsigned int remoteHost = 0; unsigned short int remotePort = 0; unsigned short int localPort = 0; unsigned int daemon = 0; if ( 1 == argc ) { usage( argv[0] ); } opterr = 0; while ( ( c = getopt( argc, argv, ":hdfl:vx:y:" ) ) != EOF ) { switch ( c ) { case 'd': daemon++; break; case 'f': supportftp++; break; case 'l': localPort = htons( ( unsigned short int )strtoul( optarg, NULL, 0 ) ); break; case 'x': remoteHost = resolveHost( optarg ); break; case 'y': remotePort = htons( ( unsigned short int )strtoul( optarg, NULL, 0 ) ); break; case 'v': fprintf( stderr, "%s ver "VERSION"\n", argv[0] ); return( EXIT_SUCCESS ); case 'h': case '?': default : usage( argv[0] ); break; } /* end of switch */ } /* end of while */ argc -= optind; argv += optind; if ( 0 == remoteHost || 0 == remotePort || 0 == localPort ) { fprintf( stderr, "Checking your [-l localPort] [-x remoteHost] [-y remotePort]\n" ); return( EXIT_FAILURE ); } if ( ( c = sysconf( _SC_OPEN_MAX ) ) < 0 ) { fprintf( stderr, "sysconf failed\n" ); } else { fprintf( stderr, "sysconf( _SC_OPEN_MAX ) = %d\n", c ); } memset( &res, 0, sizeof( struct rlimit ) ); if ( getrlimit( RLIMIT_NOFILE, &res ) < 0 ) { perror( "getrlimit RLIMIT_NOFILE" ); } else { fprintf ( stderr, "rlim_cur = %d rlim_max = %d\n", ( int )res.rlim_cur, ( int )res.rlim_max ); } #ifdef Aix res.rlim_cur = c; #else res.rlim_cur = res.rlim_max; #endif if ( setrlimit( RLIMIT_NOFILE, &res ) < 0 ) { perror( "setrlimit RLIMIT_NOFILE" ); } else { fprintf( stderr, "Changing ... ...\n" ); } memset( &res, 0, sizeof( struct rlimit ) ); if ( getrlimit( RLIMIT_NOFILE, &res ) < 0 ) { perror( "getrlimit RLIMIT_NOFILE" ); } else { fprintf ( stderr, "rlim_cur = %d rlim_max = %d\n", ( int )res.rlim_cur, ( int )res.rlim_max ); } if ( daemon ) { daemon_init( "/", 0 ); } init_signal(); acceptSocket = initTcpServer( localPort ); tcprelay( remoteHost, remotePort ); return( EXIT_SUCCESS ); } /* end of main */ /************************************************************************/