diff --git a/cmdline.c b/cmdline.c index fadccb8..a88448a 100644 --- a/cmdline.c +++ b/cmdline.c @@ -45,7 +45,7 @@ void cmdline_parser_print_help (void) { cmdline_parser_print_version (); printf( "Usage: %s [OPTIONS]...\n" -"Build generic tunnels trough HTTPS proxies using HTTP authentication\n" +"Build generic tunnels through HTTPS proxies using HTTP authentication\n" "\n" "Standard options:\n" // FIXME: " -c, --config=FILE Read config options from file\n" @@ -59,6 +59,7 @@ void cmdline_parser_print_help (void) { " -e, --encrypt SSL encrypt data between local proxy and destination\n" " -E, --encrypt-proxy SSL encrypt data between client and local proxy\n" " -X, --encrypt-remproxy SSL encrypt data between local and remote proxy\n" +" -L (legacy) enforce TLSv1 connection\n" #endif "\n" "Additional options for specific features:\n" @@ -72,6 +73,7 @@ void cmdline_parser_print_help (void) { " -N, --ntlm Use NTLM based authentication\n" " -t, --domain=STRING NTLM domain (default: autodetect)\n" " -H, --header=STRING Add additional HTTP headers to send to proxy\n" +" -o STRING send custom Host Header\n" #ifdef SETPROCTITLE " -x, --proctitle=STRING Use a different process title\n" #endif @@ -132,6 +134,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->encryptproxy_given = 0; args_info->encryptremproxy_given = 0; args_info->proctitle_given = 0; + args_info->enforcetls1_given = 0; + args_info->host_given = 0; /* No... we can't make this a function... -- Maniac */ #define clear_args() \ @@ -157,6 +161,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->encryptproxy_flag = 0; \ args_info->encryptremproxy_flag = 0; \ args_info->proctitle_arg = NULL; \ + args_info->enforcetls1_flag = 0; \ + args_info->host_arg = NULL; \ } clear_args(); @@ -189,6 +195,8 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { "remproxy", 1, NULL, 'r' }, { "remproxyauth", 1, NULL, 'R' }, { "proctitle", 1, NULL, 'x' }, + { "host", 1, NULL, 'o' }, + { "tlsenforce", 1, NULL, 'L' }, { "header", 1, NULL, 'H' }, { "verbose", 0, NULL, 'v' }, { "ntlm", 0, NULL, 'N' }, @@ -201,9 +209,9 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { NULL, 0, NULL, 0 } }; - c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXq", long_options, &option_index); + c = getopt_long (argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo", long_options, &option_index); #else - c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXq" ); + c = getopt( argc, argv, "hVia:u:s:t:F:p:P:r:R:d:H:x:nvNeEXqLo" ); #endif if (c == -1) @@ -262,6 +270,18 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->proctitle_arg = gengetopt_strdup (optarg); break; + case 'L': + args_info->enforcetls1_given = 1; + message("Enforcing TLSv1"); + args_info->enforcetls1_flag = 1; + break; + + case 'o': + args_info->host_given = 1; + message("Host-header override enabled\n"); + args_info->host_arg = gengetopt_strdup (optarg); + break; + case 'u': /* Username to send to HTTPS proxy for authentication. */ if (args_info->user_given) { fprintf (stderr, "%s: `--user' (`-u'), `--proxyauth' (`-P') or `--passfile' (`-F') option given more than once\n", PACKAGE); @@ -461,10 +481,11 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar if ( args_info->proxy_arg == NULL ) { if ( ((tmp = getenv("http_proxy")) != NULL) || ((tmp = getenv("HTTP_PROXY")) != NULL) ) { - int r; + //int r; char * temp; temp = malloc( 56+1 ); - r = sscanf( tmp, "http://%56[^/]/", temp ); + sscanf( tmp, "http://%56[^/]/", temp ); + //r = sscanf( tmp, "http://%56[^/]/", temp ); // message( "r = '%d'\ntemp = '%s'\n", r, temp); args_info->proxy_given = 1; diff --git a/cmdline.h b/cmdline.h index 2eccab7..01a92ad 100644 --- a/cmdline.h +++ b/cmdline.h @@ -48,6 +48,8 @@ struct gengetopt_args_info { int encryptproxy_flag; /* Turn on client to proxy SSL encryption (def=off).*/ int encryptremproxy_flag; /* Turn on local to remote proxy SSL encryption (def=off).*/ char *proctitle_arg; /* Override process title (default=off). */ + int enforcetls1_flag; /* Override default and enforce TLSv1 */ + char *host_arg; /* Optional Host Header */ int help_given; /* Whether help was given. */ int version_given; /* Whether version was given. */ int user_given; /* Whether user was given. */ @@ -71,6 +73,8 @@ struct gengetopt_args_info { int encryptproxy_given; /* Whether encrypt was given */ int encryptremproxy_given; /* Whether encrypt was given */ int proctitle_given; /* Whether to override process title */ + int enforcetls1_given; /* Wheter to enforce TLSv1 */ + int host_given; /* Wheter we override the Host Header */ }; int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *args_info ); diff --git a/http.c b/http.c index 3b7f6b9..eb9f88f 100644 --- a/http.c +++ b/http.c @@ -105,11 +105,11 @@ void proxy_protocol(PTSTREAM *pts) { if (args_info.remproxy_given ) { if( args_info.verbose_flag ) message( "\nTunneling to %s (remote proxy)\n", args_info.remproxy_arg ); - sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.remproxy_arg, args_info.remproxy_arg ); + sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.remproxy_arg, args_info.host_arg ? args_info.host_arg : args_info.remproxy_arg ); } else { if( args_info.verbose_flag ) message( "\nTunneling to %s (destination)\n", args_info.dest_arg ); - sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.dest_arg ); + sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.host_arg ? args_info.host_arg : args_info.dest_arg ); } if ( args_info.user_given && args_info.pass_given ) { @@ -163,7 +163,7 @@ void proxy_protocol(PTSTREAM *pts) { if( args_info.verbose_flag ) message( "\nTunneling to %s (destination)\n", args_info.dest_arg ); - sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.dest_arg); + sprintf( buf, "CONNECT %s HTTP/1.1\r\nHost: %s\r\n", args_info.dest_arg, args_info.host_arg ? args_info.host_arg : args_info.dest_arg); if ( args_info.remuser_given && args_info.rempass_given ) strzcat( buf, "Proxy-Authorization: Basic %s\r\n", basicauth(args_info.remuser_arg, args_info.rempass_arg )); diff --git a/io.c b/io.c index acbcde7..e8df31a 100644 --- a/io.c +++ b/io.c @@ -29,6 +29,8 @@ #include "proxytunnel.h" #include "io.h" +#define ACTIVE 1 +#define CLOSED 0 /* * Read one line of data from the tunnel. Line is terminated by a @@ -41,7 +43,7 @@ int readline(PTSTREAM *pts) { /* Read one character at a time into buf, until a newline is encountered. */ while ( c != 10 && ( i < SIZE - 1 ) ) { - if( stream_read( pts, &c ,1) < 0) { + if( stream_read( pts, &c ,1) <= 0) { my_perror( "Socket read error" ); exit( 1 ); } @@ -55,8 +57,8 @@ int readline(PTSTREAM *pts) { if( args_info.verbose_flag ) { /* Copy line of data into dstr without trailing newline */ - char *dstr = malloc(sizeof(buf) + 1); - strlcpy( dstr, buf, strlen(buf) - 1); + char *dstr = malloc(strlen(buf) + 1); + strncpy( dstr, buf, strlen(buf)); if (strcmp(dstr, "")) message( " <- %s\n", dstr ); } @@ -81,11 +83,17 @@ void cpio(PTSTREAM *stream1, PTSTREAM *stream2) { /* We are never interested in sockets being available for write */ FD_ZERO( &writefds ); + + /* experimental timeout */ + struct timeval select_timeout; + select_timeout.tv_sec = 30; /* should be fine */ + select_timeout.tv_usec = 0; + if( args_info.verbose_flag ) message( "\nTunnel established.\n" ); - /* Only diamonds are forever :-) */ - while( 1==1 ) { + int stream_status = ACTIVE; + while( stream_status == ACTIVE ) { /* Clear the interesting socket sets */ FD_ZERO( &readfds ); FD_ZERO( &exceptfds ); @@ -99,32 +107,37 @@ void cpio(PTSTREAM *stream1, PTSTREAM *stream2) { FD_SET( stream_get_outgoing_fd(stream1), &exceptfds ); FD_SET( stream_get_incoming_fd(stream2), &exceptfds ); FD_SET( stream_get_outgoing_fd(stream2), &exceptfds ); + + /* reset the timeout, since select() does modify this struct! */ + select_timeout.tv_sec = 30; + select_timeout.tv_usec = 0; - /* Wait until something happens on the registered sockets/files */ - if ( select( max_fd + 1, &readfds, &writefds, &exceptfds, 0 ) < 0 ) { + /* Wait/timeout something happens on the registered sockets/files */ + int number_of_fds_ready; + number_of_fds_ready = select( max_fd + 1, &readfds, &writefds, &exceptfds, &select_timeout ); + if ( number_of_fds_ready < 0 ) { perror("select error"); exit(1); } - /* - * 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 - * stream2 to stream1. Otherwise an exceptional condition - * is flagged and the program is terminated. - */ - if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) { - if ( stream_copy(stream1, stream2 ) ) - break; - } else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) { - if( stream_copy(stream2, stream1 ) ) - break; - } else { - my_perror( "Exceptional condition" ); - break; - } + if (number_of_fds_ready > 0) { + /* 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 + * stream2 to stream1. Otherwise an exceptional condition + * is flagged and the program is terminated. + */ + if ( FD_ISSET( stream_get_incoming_fd(stream1), &readfds ) ) { + if ( stream_copy(stream1, stream2 ) ) + stream_status = CLOSED; + } else if( FD_ISSET( stream_get_incoming_fd(stream2), &readfds ) ) { + if( stream_copy(stream2, stream1 ) ) + stream_status = CLOSED; + } else { + my_perror( "Exceptional condition" ); + stream_status = CLOSED; + } + } } closeall(); } - -// vim:noexpandtab:ts=4 diff --git a/ptstream.c b/ptstream.c index 6d55137..97af14f 100644 --- a/ptstream.c +++ b/ptstream.c @@ -145,13 +145,17 @@ int stream_copy(PTSTREAM *pts_from, PTSTREAM *pts_to) { /* Initiate an SSL handshake on this stream and encrypt all subsequent data */ int stream_enable_ssl(PTSTREAM *pts) { #ifdef USE_SSL - SSL_METHOD *meth; + const SSL_METHOD *meth; SSL *ssl; SSL_CTX *ctx; /* Initialise the connection */ SSLeay_add_ssl_algorithms(); - meth = SSLv23_client_method(); + if (args_info.enforcetls1_flag) { + meth = TLSv1_client_method(); + } else { + meth = SSLv23_client_method(); + } SSL_load_error_strings(); ctx = SSL_CTX_new (meth); diff --git a/readpassphrase.c b/readpassphrase.c index 1870700..b107624 100644 --- a/readpassphrase.c +++ b/readpassphrase.c @@ -135,8 +135,13 @@ restart: oterm.c_lflag |= ECHO; } - if (!(flags & RPP_STDIN)) - (void)write(output, prompt, strlen(prompt)); + if (!(flags & RPP_STDIN)) { + ssize_t bytes_written = write(output, prompt, strlen(prompt)); + if (bytes_written != strlen(prompt)) { + message("Error on writing bytes to prompt\n"); + } + } + end = buf + bufsiz - 1; for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) { if (p < end) { @@ -153,8 +158,12 @@ restart: } *p = '\0'; save_errno = errno; - if (!(term.c_lflag & ECHO)) - (void)write(output, "\n", 1); + if (!(term.c_lflag & ECHO)) { + ssize_t bytes_written = write(output, "\n", 1); + if (bytes_written != 1) { + message("Error writing one byte to prompt\n"); + } + } /* Restore old terminal settings and signals. */ if (memcmp(&term, &oterm, sizeof(term)) != 0) {