diff --git a/CHANGES b/CHANGES index dca89b4..5c62f5e 100755 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Changes to proxytunnel version 1.6.4 -- xxx +Changes to proxytunnel version 1.6.4 -- Mon Feb 12 21:45:06 CEST 2007 - Allow multiple '-H' options (headers), total size of the headers should not exceed 1k. @@ -10,6 +10,8 @@ Changes to proxytunnel version 1.6.4 -- xxx - Change error message on 'connection closed' in analyze_HTTP - Reworked debug-output (dag-) - Signal handling (dag-) +- Applied (reworked) changes from Mark Cave-Ayland to support -E option + encrypting data to the proxy with SSL (untested by me) Changes to proxytunnel version 1.6.3 -- Mon Apr 10 12:48:02 CEST 2006 diff --git a/CREDITS b/CREDITS index aa7d0ba..13ec531 100644 --- a/CREDITS +++ b/CREDITS @@ -18,7 +18,7 @@ people. Stephane Engel at macchiati.org - Fix for broken proxy Mike Frysinger - Makefile fix, 64bit fix Alex Peuchert proxytunnel@peuchert.de - SSL/Encrypt support - + Mark.Cave-Ayland @ ilande.co.uk - SSL to Proxy, Streams Furthermore we would like to thank the wonderful people at SourceForge for hosting our development. diff --git a/Makefile b/Makefile index 6a3d8ab..87a896b 100755 --- a/Makefile +++ b/Makefile @@ -50,7 +50,8 @@ OBJ = proxytunnel.o \ readpassphrase.o \ messages.o \ cmdline.o \ - ntlm.o + ntlm.o \ + ptstream.o proxytunnel: $(OBJ) $(CC) -o $(PROGNAME) $(CFLAGS) $(OBJ) $(LDFLAGS) diff --git a/cmdline.c b/cmdline.c index 6441328..e1e8300 100755 --- a/cmdline.c +++ b/cmdline.c @@ -59,6 +59,7 @@ cmdline_parser_print_help (void) #endif #ifdef USE_SSL " -e --encrypt encrypt the communication using SSL\n" +" -E --encrypt-proxy encrypt the communitation between the client and the proxy using SSL\n" #endif #ifdef SETPROCTITLE " -x STRING --proctitle=STRING Set the process-title to STRING\n" @@ -132,6 +133,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->header_given = 0; args_info->domain_given = 0; args_info->encrypt_given = 0; + args_info->encryptproxy_given = 0; args_info->proctitle_given = 0; /* No... we can't make this a function... -- Maniac */ @@ -151,6 +153,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->quiet_flag = 0; \ args_info->standalone_arg = 0; \ args_info->encrypt_flag = 0; \ + args_info->encryptproxy_flag = 0; \ args_info->proctitle_arg = NULL; \ } @@ -171,32 +174,33 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar /* Struct option: Name, Has_arg, Flag, Value */ static struct option long_options[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'V' }, - { "user", 1, NULL, 'u' }, - { "pass", 1, NULL, 's' }, - { "domain", 1, NULL, 't' }, - { "uservar", 1, NULL, 'U' }, - { "passvar", 1, NULL, 'S' }, - { "proxy", 1, NULL, 'p' }, - { "proxyhost", 1, NULL, 'g' }, - { "proxyport", 1, NULL, 'G' }, - { "dest", 1, NULL, 'd' }, - { "remproxy", 1, NULL, 'r' }, - { "proctitle", 1, NULL, 'x' }, - { "header", 1, NULL, 'H' }, - { "verbose", 0, NULL, 'v' }, - { "ntlm", 0, NULL, 'N' }, - { "inetd", 0, NULL, 'i' }, - { "standalone", 1, NULL, 'a' }, - { "quiet", 0, NULL, 'q' }, - { "encrypt", 0, NULL, 'e' }, + { "help", 0, NULL, 'h' }, + { "version", 0, NULL, 'V' }, + { "user", 1, NULL, 'u' }, + { "pass", 1, NULL, 's' }, + { "domain", 1, NULL, 't' }, + { "uservar", 1, NULL, 'U' }, + { "passvar", 1, NULL, 'S' }, + { "proxy", 1, NULL, 'p' }, + { "proxyhost", 1, NULL, 'g' }, + { "proxyport", 1, NULL, 'G' }, + { "dest", 1, NULL, 'd' }, + { "remproxy", 1, NULL, 'r' }, + { "proctitle", 1, NULL, 'x' }, + { "header", 1, NULL, 'H' }, + { "verbose", 0, NULL, 'v' }, + { "ntlm", 0, NULL, 'N' }, + { "inetd", 0, NULL, 'i' }, + { "standalone", 1, NULL, 'a' }, + { "quiet", 0, NULL, 'q' }, + { "encrypt", 0, NULL, 'e' }, + { "encrypt-proxy", 0, NULL, 'E' }, { NULL, 0, NULL, 0 } }; - c = getopt_long (argc, argv, "hVia:u:s:t:U:S:p:r:d:H:x:nvNeq", long_options, &option_index); + c = getopt_long (argc, argv, "hVia:u:s:t:U:S:p:r:d:H:x:nvNeEq", long_options, &option_index); #else - c = getopt( argc, argv, "hVia:u:s:t:U:S:p:r:d:H:x:nvNeq" ); + c = getopt( argc, argv, "hVia:u:s:t:U:S:p:r:d:H:x:nvNeEq" ); #endif if (c == -1) break; /* Exit from `while (1)' loop. */ @@ -214,6 +218,12 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar if( args_info->verbose_flag ) message("SSL enabled\n"); break; + + case 'E': /* Turn on client to proxy SSL encryption */ + args_info->encryptproxy_flag = !(args_info->encryptproxy_flag); + if( args_info->verbose_flag ) + message("SSL client to proxy enabled\n"); + break; #endif case 'i': /* Run from inetd. */ diff --git a/cmdline.h b/cmdline.h index da7fd23..f29d860 100755 --- a/cmdline.h +++ b/cmdline.h @@ -41,25 +41,28 @@ struct gengetopt_args_info { int quiet_flag; /* Turn on quiet mode (default=off). */ int standalone_arg; /* Turn on stdalone (-a) on port */ int encrypt_flag; /* Turn on SSL encryption (default=off). */ + int encryptproxy_flag;/* Turn on client to proxy SSL encryption (def=off).*/ + char * proctitle_arg; /* Override process title (default=off). */ - int help_given; /* Whether help was given. */ - int version_given; /* Whether version was given. */ - int user_given; /* Whether user was given. */ - int pass_given; /* Whether pass was given. */ - int domain_given; /* Whether domain was given. */ - int proxy_given; /* Whether proxyhost was given. */ - int proxyhost_given; /* Whether proxyhost was given. */ - int proxyport_given; /* Whether proxyport was given. */ - int dest_given; /* Whether dest was given. */ - int remproxy_given; /* Whether remproxy was given. */ - int verbose_given; /* Whether verbose was given. */ - int ntlm_given; /* Whether ntlm was given. */ - int inetd_given; /* Whether inetd was given. */ - int quiet_given; /* Whether quiet mode was given. */ - int header_given; /* Whenther extra headers are given */ - int encrypt_given; /* Whether encrypt was given */ - int proctitle_given; /* Whether to override process title */ + int help_given; /* Whether help was given. */ + int version_given; /* Whether version was given. */ + int user_given; /* Whether user was given. */ + int pass_given; /* Whether pass was given. */ + int domain_given; /* Whether domain was given. */ + int proxy_given; /* Whether proxyhost was given. */ + int proxyhost_given; /* Whether proxyhost was given. */ + int proxyport_given; /* Whether proxyport was given. */ + int dest_given; /* Whether dest was given. */ + int remproxy_given; /* Whether remproxy was given. */ + int verbose_given; /* Whether verbose was given. */ + int ntlm_given; /* Whether ntlm was given. */ + int inetd_given; /* Whether inetd was given. */ + int quiet_given; /* Whether quiet mode was given. */ + int header_given; /* Whether extra headers are given */ + int encrypt_given; /* Whether encrypt was given */ + int encryptproxy_given; /* Whether encrypt was given */ + int proctitle_given; /* Whether to override process title */ } ; int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *args_info ); diff --git a/config.h b/config.h index 5330032..2d13b81 100755 --- a/config.h +++ b/config.h @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define VERSION "1.6.3" +#define VERSION "1.6.4" #define PACKAGE "Proxytunnel" #define PURPOSE "Build generic tunnels through HTTPS proxies" #define AUTHORS "Jos Visser (Muppet) , Mark Janssen (Maniac) " diff --git a/http.c b/http.c index 2511cbd..303f6bd 100644 --- a/http.c +++ b/http.c @@ -26,8 +26,8 @@ #include #include -#include "io.h" #include "proxytunnel.h" +#include "io.h" #include "basicauth.h" #include "ntlm.h" @@ -35,7 +35,7 @@ * Analyze the proxy's HTTP response. This must be a HTTP/1.? 200 OK type * header */ -void analyze_HTTP() +void analyze_HTTP(PTSTREAM *pts) { char *p = strtok( buf, " "); @@ -45,7 +45,7 @@ void analyze_HTTP() */ while (strncmp( p, "HTTP/", 5) != 0 ) { - if ( readline() ) + if ( readline(pts) ) p = strtok( buf, " "); else { @@ -76,7 +76,7 @@ void analyze_HTTP() { do { - readline(); + readline(pts); if (strncmp( buf, "Proxy-Authenticate: NTLM ", 25) == 0) { if (parse_type2((unsigned char *)&buf[25]) < 0) @@ -86,7 +86,7 @@ void analyze_HTTP() } if (ntlm_challenge == 1) { - proxy_protocol(); + proxy_protocol(pts); return; } exit( 1 ); @@ -111,7 +111,7 @@ void print_line_prefix(char *buf, char *prefix) * Execute the basic proxy protocol of CONNECT and response, until the * last line of the response has been read. The tunnel is then open. */ -void proxy_protocol() +void proxy_protocol(PTSTREAM *pts) { /* * Create the proxy CONNECT command into buf @@ -170,7 +170,7 @@ void proxy_protocol() /* * Send the CONNECT instruction to the proxy */ - if( send( sd, buf, strlen( buf ), 0 ) < 0 ) + if( stream_write( pts, buf, strlen( buf )) < 0 ) { my_perror( "Socket write error" ); exit( 1 ); @@ -181,14 +181,14 @@ void proxy_protocol() if( args_info.verbose_flag ) message( "Data received from local proxy:\n"); - analyze_HTTP(); + analyze_HTTP(pts); if (args_info.remproxy_given ) { /* * Clean buffer for next analysis */ - while ( strcmp( buf, "\r\n" ) != 0 ) readline(); + while ( strcmp( buf, "\r\n" ) != 0 ) readline(pts); if( args_info.verbose_flag ) message( "Tunneling to %s (destination)\n", args_info.dest_arg ); @@ -212,7 +212,7 @@ void proxy_protocol() /* * Send the CONNECT instruction to the proxy */ - if( send( sd, buf, strlen( buf ), 0 ) < 0 ) + if( stream_write( pts, buf, strlen( buf )) < 0 ) { my_perror( "Socket write error" ); exit( 1 ); @@ -224,7 +224,7 @@ void proxy_protocol() if( args_info.verbose_flag ) message( "Received from remote proxy:\n"); - analyze_HTTP(); + analyze_HTTP(pts); } /* @@ -235,7 +235,7 @@ void proxy_protocol() ntlm_challenge = 2; } else { do { - readline(); + readline(pts); } while ( strcmp( buf, "\r\n" ) != 0 ); } } diff --git a/io.c b/io.c index 84fc480..da72b1b 100644 --- a/io.c +++ b/io.c @@ -29,19 +29,12 @@ #include "proxytunnel.h" #include "io.h" -#ifdef USE_SSL /* Override copy functions */ -#define COPY_TO(fd) copy_to_SSL(fd, ssl) -#define COPY_FROM(fd) copy_from_SSL(ssl, fd) -#else -#define COPY_TO(fd) copy(fd, sd) -#define COPY_FROM(fd) copy(sd, fd) -#endif /* * Read one line of data from the tunnel. Line is terminated by a * newline character. Result is stored in buf. */ -int readline() +int readline(PTSTREAM *pts) { char *p = buf; char c = 0; @@ -53,7 +46,7 @@ int readline() */ while ( c != 10 && ( i < SIZE - 1 ) ) { - if( recv( sd, &c ,1 ,0 ) < 0) + if( stream_read( pts, &c ,1) < 0) { my_perror( "Socket read error" ); exit( 1 ); @@ -76,144 +69,26 @@ int readline() return strlen( buf ); } -/* - * Copy a block of data from one socket descriptor to another. A true - * return code signifies EOF on the from socket descriptor. - */ -int copy(int from, int to) -{ - int n; - - /* - * Read a buffer from the source socket - */ - if ( ( n = read( from, buf, SIZE ) ) < 0 ) - { - my_perror( "Socket read error" ); - exit( 1 ); - } - - /* - * If we have read 0 bytes, there is an EOF on src - */ - if( n==0 ) - return 1; - - /* - * Write the buffer to the destination socket - */ - if ( write( to, buf, n ) != n ) - { - my_perror( "Socket write error" ); - exit( 1 ); - } - - /* - * We're not yet at EOF - */ - return 0; -} - -#ifdef USE_SSL -int copy_to_SSL(int from, SSL* to) -{ - int n; - - /* - * Read a buffer from the source socket - */ - if ( ( n = read( from, buf, SIZE ) ) < 0 ) - { - my_perror( "Socket read error" ); - exit( 1 ); - } - - /* - * If we have read 0 bytes, there is an EOF on src - */ - if( n==0 ) - return 1; - - /* - * Write the buffer to the destination socket - */ - if ( SSL_write( to, buf, n ) != n ) - { - my_perror( "Socket write error" ); - exit( 1 ); - } - - /* - * We're not yet at EOF - */ - return 0; -} - -int copy_from_SSL(SSL* from, int to) -{ - int n; - - /* - * Read a buffer from the source socket - */ - if ( ( n = SSL_read( from, buf, SIZE ) ) < 0 ) - { - my_perror( "Socket read error" ); - exit( 1 ); - } - - /* - * If we have read 0 bytes, there is an EOF on src - */ - if( n==0 ) - return 1; - - /* - * Write the buffer to the destination socket - */ - if ( write( to, buf, n ) != n ) - { - my_perror( "Socket write error" ); - exit( 1 ); - } - - /* - * We're not yet at EOF - */ - return 0; -} -#endif /* USE_SSL */ - /* - * Move into a loop of copying data to and from the tunnel. - * stdin (fd 0) and stdout (fd 1) are the file descriptors - * for the connected application, sd is the file descriptor - * of the tunnel. + * Bond stream1 and stream2 together; any data received in stream1 is relayed + * to stream2, and vice-versa. */ -void cpio() +void cpio(PTSTREAM *stream1, PTSTREAM *stream2) { fd_set readfds; fd_set writefds; fd_set exceptfds; - int max_fd; - int out_fd; + int in_max_fd, out_max_fd, max_fd; -#ifdef USE_SSL - if( args_info.encrypt_flag ) - out_fd = SSL_get_fd(ssl); - else - out_fd = sd; -#else - out_fd = sd; -#endif /* * Find the biggest file descriptor for select() */ - max_fd = MAX( read_fd,write_fd ); - max_fd = MAX( max_fd, out_fd ); + in_max_fd = MAX(stream_get_incoming_fd(stream1), stream_get_incoming_fd(stream2)); + out_max_fd = MAX(stream_get_outgoing_fd(stream1), stream_get_outgoing_fd(stream2)); + max_fd = MAX(in_max_fd, out_max_fd); /* * We're never interested in sockets being available for write. @@ -235,18 +110,18 @@ void cpio() FD_ZERO( &exceptfds ); /* - * We want to know whether stdin or sd is ready for reading + * We want to know whether stream1 or stream2 is ready for reading */ - FD_SET( read_fd, &readfds ); - FD_SET( out_fd, &readfds ); + FD_SET( stream_get_incoming_fd(stream1), &readfds ); + FD_SET( stream_get_incoming_fd(stream2), &readfds ); /* - * And we want to know about exceptional conditions on either - * stdin, stdout or the tunnel + * And we want to know about exceptional conditions on either stream */ - FD_SET( read_fd, &exceptfds ); - FD_SET( write_fd, &exceptfds ); - FD_SET( out_fd, &exceptfds ); + FD_SET( stream_get_incoming_fd(stream1), &exceptfds ); + FD_SET( stream_get_outgoing_fd(stream1), &exceptfds ); + FD_SET( stream_get_incoming_fd(stream2), &exceptfds ); + FD_SET( stream_get_outgoing_fd(stream2), &exceptfds ); /* * Wait until something happens on one of the registered @@ -260,37 +135,21 @@ void cpio() } /* - * Is stdin ready for read? If so, copy a block of data - * from stdin to the tunnel. Or else if the tunnel socket + * Is stream1 ready for read? If so, copy a block of data + * from stream1 to stream2. Or else if stream2 * is ready for read, copy a block of data from the - * tunnel to stdout. Otherwise an exceptional condition + * stream2 to stream1. Otherwise an exceptional condition * is flagged and the program is terminated. */ - if ( FD_ISSET( read_fd, &readfds ) ) + if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) { - if( args_info.encrypt_flag ) - { - if ( COPY_TO(read_fd ) ) - break; - } - else - { - if ( copy(read_fd, sd ) ) - break; - } + if ( stream_copy(stream1, stream2 ) ) + break; } - else if( FD_ISSET( sd, &readfds ) ) + else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) { - if( args_info.encrypt_flag ) - { - if( COPY_FROM(write_fd ) ) - break; - } - else - { - if( copy(sd,write_fd ) ) - break; - } + if( stream_copy(stream2, stream1 ) ) + break; } else { diff --git a/io.h b/io.h index 128cd5a..b162b2c 100644 --- a/io.h +++ b/io.h @@ -18,7 +18,5 @@ */ /* io.h */ -int readline(); -int copy(int from, int to); -void cpio(); - +int readline(PTSTREAM *pts); +void cpio(PTSTREAM *stream1, PTSTREAM *stream2); diff --git a/proxytunnel.c b/proxytunnel.c index 75dc282..ed060b0 100755 --- a/proxytunnel.c +++ b/proxytunnel.c @@ -33,11 +33,11 @@ #include #include +#include "proxytunnel.h" #include "io.h" #include "config.h" #include "cmdline.h" #include "basicauth.h" -#include "proxytunnel.h" #include "ntlm.h" /* Define DARWIN if compiling on MacOS-X (Darwin), to work around some @@ -50,12 +50,6 @@ int read_fd=0; /* The file descriptor to read from */ int write_fd=1; /* The file destriptor to write to */ -#ifdef USE_SSL -SSL_CTX* ctx; -SSL* ssl; -SSL_METHOD *meth; -#endif - /* * Kill the program (signal handler) */ @@ -67,12 +61,13 @@ void signal_handler( int signal ) } /* - * Create and connect the socket that connects to the proxy. After - * this routine the sd socket is connected to the proxy. + * Create and connect the socket that connects to the proxy. Returns + * the socket that is connected to the proxy */ -void tunnel_connect() { +int tunnel_connect() { struct sockaddr_in sa; struct hostent *he; + int sd; /* * Create the socket @@ -131,26 +126,11 @@ void tunnel_connect() { /* Make sure we get warned when someone hangs up on us */ signal(SIGHUP,signal_handler); + + /* Return the socket */ + return sd; } -#ifdef USE_SSL -/* - * Do the SSL handshake. - */ -void do_ssl() -{ - SSLeay_add_ssl_algorithms(); - meth = SSLv2_client_method(); - SSL_load_error_strings(); - - ctx = SSL_CTX_new (meth); - - ssl = SSL_new (ctx); - - SSL_set_fd (ssl, sd); - SSL_connect (ssl); -} -#endif /* * Leave a goodbye message @@ -171,30 +151,12 @@ void closeall() { #endif /* - * Close all files we deal with + * Close all streams */ - close(0); - close(1); - - if ( sd != 0 ) - close( sd ); - - -#ifdef USE_SSL - if( args_info.encrypt_flag ) - { - SSL_free (ssl); - SSL_CTX_free (ctx); - } -#else - close( sd ); -#endif - - if( read_fd != write_fd ) /* When not running from inetd */ - { - close( write_fd ); - } - close( read_fd ); + if (stunnel) + stream_close(stunnel); + if (std) + stream_close(std); } /* @@ -211,6 +173,10 @@ void do_daemon() char buf[80]; unsigned char addr[4]; + /* Socket descriptor */ + int sd; + + if ( ( listen_sd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { my_perror( "Server socket creation failed" ); @@ -297,12 +263,26 @@ void do_daemon() { read_fd = write_fd = sd_client; - /* Main processing */ - tunnel_connect(); - proxy_protocol(); + /* Create a stdin/out stream */ + std = stream_open(read_fd, write_fd); + + /* Create a tunnel stream */ + sd = tunnel_connect(); + stunnel = stream_open(sd, sd); + + /* If --encrypt-proxy is specified, connect to the proxy using SSL */ +#ifdef USE_SSL + if ( args_info.encryptproxy_flag ) + stream_enable_ssl(stunnel); +#endif + + /* Open the tunnel */ + proxy_protocol(stunnel); + + /* If --encrypt is specified, wrap all traffic after the proxy handoff in SSL */ #ifdef USE_SSL if( args_info.encrypt_flag ) - do_ssl(); + stream_enable_ssl(stunnel); #endif #ifdef SETPROCTITLE if( ! args_info.proctitle_given ) @@ -313,8 +293,9 @@ void do_daemon() if( args_info.proctitle_given ) message( "Setting process-title is not supported in this build\n"); #endif - - cpio(); + + /* Run the tunnel - we should stay here indefinitely */ + cpio(std, stunnel); ///// exit( 0 ); } @@ -339,6 +320,13 @@ void do_daemon() */ int main( int argc, char *argv[] ) { + /* Socket descriptor */ + int sd; + + /* Clear all stream variables (so we know whether we need to clear up) */ + stunnel = NULL; + std = NULL; + program_name = argv[0]; /* @@ -356,7 +344,7 @@ int main( int argc, char *argv[] ) * different mainline is needed... * - Set a signal for the hangup (HUP) signal * - Optionally create the proxy basic authentication cookie - * - Connect the sd socket to the proxy + * - Connect to the proxy * - Execute the proxy protocol to connect it to the origin server * - Enter copy in-out mode to channel data hence and forth */ @@ -386,6 +374,16 @@ int main( int argc, char *argv[] ) make_basicauth(); } + /* + * Only one of -E (SSL encrypt client to proxy connection) or -e (SSL encrypt tunnel data) + * can be specified. + */ + if (args_info.encryptproxy_flag && args_info.encrypt_flag) + { + message("Error: only one of --encrypt-proxy and --encrypt can be specified for a tunnel\n"); + exit( 1 ); + } + /* Do we need to run as a standalone daemon? */ if ( args_info.standalone_arg > 0 ) { @@ -400,12 +398,26 @@ int main( int argc, char *argv[] ) write_fd=0; } - /* Main processing */ - tunnel_connect(); - proxy_protocol(); + /* Create a stdin/out stream */ + std = stream_open(read_fd, write_fd); + + /* Create a tunnel stream */ + sd = tunnel_connect(); + stunnel = stream_open(sd, sd); + + /* If --encrypt-proxy is specified, connect to the proxy using SSL */ +#ifdef USE_SSL + if ( args_info.encryptproxy_flag ) + stream_enable_ssl(stunnel); +#endif + + /* Open the tunnel */ + proxy_protocol(stunnel); + + /* If --encrypt is specified, wrap all traffic after the proxy handoff in SSL */ #ifdef USE_SSL if( args_info.encrypt_flag ) - do_ssl(); + stream_enable_ssl(stunnel); #endif #ifdef SETPROCTITLE if( ! args_info.proctitle_given ) @@ -417,8 +429,12 @@ int main( int argc, char *argv[] ) message( "Setting process-title is not supported in this build\n"); #endif - cpio(); + /* Run the tunnel - we should stay here indefinitely */ + cpio(std, stunnel); } + /* If we do happen to get here, clean up */ + closeall(); + exit( 0 ); } diff --git a/proxytunnel.h b/proxytunnel.h index 45c60f4..2a2d243 100644 --- a/proxytunnel.h +++ b/proxytunnel.h @@ -19,22 +19,15 @@ /* proxytunnel.h */ -#ifdef USE_SSL -#include -#include -#include -#include -#endif - #include "cmdline.h" +#include "ptstream.h" void message( char *s, ... ); void my_perror( char *msg ); void signal_handler( int signal ); -void tunnel_connect(); +int tunnel_connect(); void analyze_HTTP(); void proxy_protocol(); -void do_ssl(); void closeall(); void do_daemon(); void initsetproctitle(int argc, char *argv[]); @@ -46,16 +39,13 @@ char * readpassphrase(const char *, char *, size_t, int); char * getpass_x(const char *prompt); /* Globals */ -int sd; /* The tunnel's socket descriptor */ int read_fd; /* The file descriptor to read from */ int write_fd; /* The file destriptor to write to */ char *program_name; /* Guess what? */ int i_am_daemon; /* Also... */ -#ifdef USE_SSL -SSL_CTX* ctx; -SSL* ssl; -#endif +PTSTREAM *stunnel; /* The stream representing the socket from us to the proxy */ +PTSTREAM *std; /* The stream representing stdin/stdout */ /* * All the command line options diff --git a/ptstream.c b/ptstream.c new file mode 100644 index 0000000..ef03f17 --- /dev/null +++ b/ptstream.c @@ -0,0 +1,247 @@ +/* Proxytunnel - (C) 2001-2006 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ptstream.c */ + +#include +#include +#include +#include +#include +#include + +#include "proxytunnel.h" + + +/* + * Open a stream for incoming and outgoing data with the specified fds + */ + +PTSTREAM *stream_open(int incoming_fd, int outgoing_fd) +{ + PTSTREAM *pts; + + /* Initialise the structure and store the file descriptor */ + pts = malloc(sizeof(PTSTREAM)); + pts->incoming_fd = incoming_fd; + pts->outgoing_fd = outgoing_fd; + pts->ssl = NULL; + pts->ctx = NULL; + + /* Return a pointer to the structure */ + return pts; +} + + +/* + * Close a stream + */ + +int stream_close(PTSTREAM *pts) +{ + /* Close the incoming fd */ + if (pts->incoming_fd != 0) + close(pts->incoming_fd); + + /* Close the outgoing fd */ + if (pts->outgoing_fd != 0) + close(pts->outgoing_fd); + + /* Destroy the SSL context */ + if (pts->ssl) + { +#ifdef USE_SSL + SSL_free (pts->ssl); + SSL_CTX_free (pts->ctx); +#endif + } + + /* Free the structure */ + free(pts); + + return 1; +} + + +/* + * Read from a stream + */ + +int stream_read(PTSTREAM *pts, void *buf, size_t len) +{ + /* Read up to the specified number of bytes into the buffer */ + int bytes_read; + + if (!pts->ssl) + { + /* For a non-SSL stream... */ + bytes_read = read(pts->incoming_fd, buf, len); + } + else + { +#ifdef USE_SSL + /* For an SSL stream... */ + bytes_read = SSL_read(pts->ssl, buf, len); +#else + /* No SSL support, so must use a non-SSL stream */ + bytes_read = read(pts->incoming_fd, buf, len); +#endif + } + + return bytes_read; +} + + +/* + * Write to a stream + */ + +int stream_write(PTSTREAM *pts, void *buf, size_t len) +{ + /* Write the specified number of bytes from the buffer */ + int bytes_written; + + if (!pts->ssl) + { + /* For a non-SSL stream... */ + bytes_written = write(pts->outgoing_fd, buf, len); + } + else + { +#ifdef USE_SSL + /* For an SSL stream... */ + bytes_written = SSL_write(pts->ssl, buf, len); +#else + /* No SSL support, so must use a non-SSL stream */ + bytes_written = write(pts->outgoing_fd, buf, len); +#endif + } + + return bytes_written; +} + + +/* + * Copy a block of data from one stream to another. A true + * return code signifies EOF on the from socket descriptor. + */ + +int stream_copy(PTSTREAM *pts_from, PTSTREAM *pts_to) +{ + char buf[SIZE]; + int n; + + /* + * Read a buffer from the source socket + */ + if ( ( n = stream_read( pts_from, buf, SIZE ) ) < 0 ) + { + my_perror( "Socket read error" ); + exit( 1 ); + } + + /* + * If we have read 0 bytes, there is an EOF on src + */ + if( n==0 ) + return 1; + + /* + * Write the buffer to the destination socket + */ + if ( stream_write( pts_to, buf, n ) != n ) + { + my_perror( "Socket write error" ); + exit( 1 ); + } + + /* + * We're not yet at EOF + */ + return 0; +} + + +/* + * Initiate an SSL handshake on this stream and encrypt all subsequent data + */ + +int stream_enable_ssl(PTSTREAM *pts) +{ +#ifdef USE_SSL + SSL_METHOD *meth; + SSL *ssl; + SSL_CTX *ctx; + + /* Initialise the connection */ + SSLeay_add_ssl_algorithms(); + meth = SSLv2_client_method(); + SSL_load_error_strings(); + + ctx = SSL_CTX_new (meth); + ssl = SSL_new (ctx); + SSL_set_rfd (ssl, stream_get_incoming_fd(pts)); + SSL_set_wfd (ssl, stream_get_outgoing_fd(pts)); + SSL_connect (ssl); + + /* Store ssl and ctx parameters */ + pts->ssl = ssl; + pts->ctx = ctx; +#else + message("Warning: stream_open(): SSL stream requested but no SSL support available; using unencrypted connection"); +#endif + + return 1; +} + + +/* + * Return the incoming_fd for a given stream + */ + +int stream_get_incoming_fd(PTSTREAM *pts) +{ + + if (!pts->ssl) + return pts->incoming_fd; + else +#ifdef USE_SSL + return SSL_get_fd(pts->ssl); +#else + return pts->incoming_fd; +#endif +} + + +/* + * Return the outgoing_fd for a given stream + */ + +int stream_get_outgoing_fd(PTSTREAM *pts) +{ + + if (!pts->ssl) + return pts->outgoing_fd; + else +#ifdef USE_SSL + return SSL_get_fd(pts->ssl); +#else + return pts->outgoing_fd; +#endif +} diff --git a/ptstream.h b/ptstream.h new file mode 100644 index 0000000..7c5eb94 --- /dev/null +++ b/ptstream.h @@ -0,0 +1,50 @@ +/* Proxytunnel - (C) 2001-2006 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* ptstream.h */ + +#ifdef USE_SSL +#include +#include +#include +#include +#endif + +typedef struct ptstream +{ + int incoming_fd; + int outgoing_fd; +#ifdef USE_SSL + SSL *ssl; + SSL_CTX *ctx; +#else + void *ssl; + void *ctx; +#endif +} PTSTREAM; + + +PTSTREAM *stream_open(int incoming_fd, int outgoing_fd); +int stream_close(PTSTREAM *pts); +int stream_read(PTSTREAM *pts, void *buf, size_t len); +int stream_write(PTSTREAM *pts, void *buf, size_t len); +int stream_copy(PTSTREAM *pts_from, PTSTREAM *pts_to); +int stream_enable_ssl(PTSTREAM *pts); +int stream_get_incoming_fd(PTSTREAM *pts); +int stream_get_outgoing_fd(PTSTREAM *pts);