diff --git a/CHANGES b/CHANGES index d6ed70b..701c9cc 100755 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,11 @@ +Changes to proxytunnel version 1.1.0 -- Sat Apr 20 16:00:00 CET 2002 + +- Added the -a (--standalone=INT) option. It is mutually exclusive with + -i (--inetd), and it instructs proxytunnel to fork in the background + as a standalone daemon, listening on connections on the specified + port and forwarding these connections through the specified + proxy/tunnel. + Changes to proxytunnel version 1.0.8 -- Fri Apr 19 10:25:00 CET 2002 - Fixed help-text when system doesn't support long-options @@ -15,7 +23,7 @@ Changes to proxytunnel version 1.0.7 -- Sat Nov 24 12:32:02 CET 2001 possible string format attacks. -- Maniac - Some code cleanup and reformatting -- Maniac - Added '-q' / '--quiet' flag to suppress status messages, Proxytunnel - can not be completely quiet and transparant. (Not when also providing + can now be completely quiet and transparent. (Not when also providing the '-v' flag naturally) -- Maniac - Changed ipbuf size to 16, which should be enough. -- Maniac @@ -50,8 +58,8 @@ Changes to proxytunnel version 1.0.3 -- Sat Nov 10 21:36:42 CET 2001 - Due to getopts, some error handling when entering incorrect command line options -- Maniac -- In addition to using http auth, which we allready had, we can now also - connect to proxy's that do NOT use http auth, simply do not specify a +- In addition to using HTTP auth, which we already had, we can now also + connect to proxy's that do NOT use HTTP auth, simply do not specify a username and password. If you specify these, they will be passed on to the proxy, otherwise we won't go into auth phase. -- Maniac diff --git a/CREDITS b/CREDITS index 3fb130e..66949ee 100644 --- a/CREDITS +++ b/CREDITS @@ -12,7 +12,7 @@ people. Andrew Griffiths" - String format fixes -Furthermore we would like to thank the wonderfull people at SourceForge +Furthermore we would like to thank the wonderful people at SourceForge for hosting our development. Jos Visser && Mark Janssen diff --git a/Makefile b/Makefile index 39abc14..0f7f5ca 100755 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ LDFLAGS = INSTALLPATH = /usr/local/bin # Solaris needs this (According to Martin Senft ) -# CFLAGS = -I /usr/include -Wall +# CFLAGS = -I/usr/include -Wall # LDFLAGS = -lsocket -lnsl PROGNAME = proxytunnel diff --git a/README b/README index 6016b4e..3ff498b 100755 --- a/README +++ b/README @@ -3,8 +3,8 @@ proxytunnel ----------- Author: Jos Visser , Mark Janssen -Date: Wed Nov 28 09:46:19 CET 2001 -Version: 1.0.7 +Date: Sat Apr 20 15:57:52 CEST 2002 +Version: 1.1.0 Hi all, @@ -19,7 +19,7 @@ with some other application, feel free, and let me know! Usage: Proxytunnel is very easy to use, when running proxytunnel with the help -option it specifies it's commandline options. +option it specifies it's command-line options. $ ./proxytunnel --help Proxytunnel 1.0.7 diff --git a/cmdline.c b/cmdline.c index d6e894d..b23d191 100755 --- a/cmdline.c +++ b/cmdline.c @@ -1,5 +1,5 @@ -/* Proxytunnel - (C) 2001 Jos Visser / Mark Janssen */ -/* Contact: josv@osp.nl / maniac@maniac.nl */ +/* Proxytunnel - (C) 2001-2002 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ /* * This program is free software; you can redistribute it and/or modify @@ -49,7 +49,10 @@ cmdline_parser_print_help (void) "Usage: %s [OPTIONS]...\n\ -h --help Print help and exit\n\ -V --version Print version and exit\n\ + -c --config=FILE Read config options from file (FIXME)\n\ -i --inetd Run from inetd (default=off)\n\ + -a INT --standalone=INT Run as standalone daemon on specified port\n\ + -f --nobackground Don't for to background in standalone mode (FIXME)\n\ -u STRING --user=STRING Username to send to HTTPS proxy for auth\n\ -s STRING --pass=STRING Password to send to HTTPS proxy for auth\n\ -g STRING --proxyhost=STRING HTTPS Proxy host to connect to\n\ @@ -61,6 +64,12 @@ cmdline_parser_print_help (void) -q --quiet Suppress messages (default=off)\n\ ", PACKAGE); + printf( "\nExamples:\n" +"%s [ -h | -V ]\n" +"%s -i [ -u user -s pass ] -g host -G port -d host -D port [ -n ] [ -v | -q ]\n" +"%s -a port [ -u user -s pass ] -g host -G port -d host -D port [ -n ] [ -v | -q ]\n", PACKAGE, PACKAGE, PACKAGE ); + + #ifndef HAVE_GETOPT_LONG printf( "\n" "Notice: This version is compiled without support for long options.\n" @@ -113,6 +122,7 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar args_info->verbose_flag = 0; \ args_info->inetd_flag = 0; \ args_info->quiet_flag = 0; \ + args_info->standalone_arg = 0; \ } clear_args(); @@ -142,13 +152,14 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar { "dottedquad", 0, NULL, 'n' }, { "verbose", 0, NULL, 'v' }, { "inetd", 0, NULL, 'i' }, + { "standalone", 1, NULL, 'a' }, { "quiet", 0, NULL, 'q' }, { NULL, 0, NULL, 0 } }; - c = getopt_long (argc, argv, "hViu:s:g:G:d:D:nvq", long_options, &option_index); + c = getopt_long (argc, argv, "hVia:u:s:g:G:d:D:nvq", long_options, &option_index); #else - c = getopt( argc, argv, "hViu:s:g:G:d:D:nvq" ); + c = getopt( argc, argv, "hVia:u:s:g:G:d:D:nvq" ); #endif if (c == -1) break; /* Exit from `while (1)' loop. */ @@ -161,9 +172,27 @@ int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *ar exit (0); case 'i': /* Run from inetd. */ + if ( args_info->standalone_arg > 0 ) + { + fprintf( stderr, "%s: '--inetd' ('-i') conflicts with '--standalone' ('-a')\n", PACKAGE ); + exit( 1 ); + } args_info->inetd_flag = !(args_info->inetd_flag); break; + case 'a': /* Run as standalone daemon */ + if ( args_info->inetd_flag ) + { + fprintf( stderr, "%s: `--standalone' (`-a') conflicts with `--inetd' (`-i')\n", PACKAGE ); + exit (1); + } + if ( ( args_info->standalone_arg = atoi( optarg ) ) < 1 ) + { + fprintf( stderr, "%s: Illegal port value for `--standalone' (`-a')\n", PACKAGE); + exit (1); + } + break; + case 'V': /* Print version and exit. */ clear_args (); cmdline_parser_print_version (); diff --git a/cmdline.h b/cmdline.h index 06db0dd..dbfad3b 100755 --- a/cmdline.h +++ b/cmdline.h @@ -1,5 +1,5 @@ -/* Proxytunnel - (C) 2001 Jos Visser / Mark Janssen */ -/* Contact: josv@osp.nl / maniac@maniac.nl */ +/* Proxytunnel - (C) 2001-2002 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ /* * This program is free software; you can redistribute it and/or modify @@ -47,6 +47,7 @@ struct gengetopt_args_info { int verbose_given; /* Whether verbose was given. */ int inetd_given; /* Whether inetd was given. */ int quiet_given; /* Whether quiet mode was given. */ + int standalone_arg; /* Turn on stdalone (-a) on port */ } ; int cmdline_parser( int argc, char * const *argv, struct gengetopt_args_info *args_info ); diff --git a/config.h b/config.h index 6e4f7f4..a4e0cd7 100755 --- a/config.h +++ b/config.h @@ -1,5 +1,5 @@ -/* Proxytunnel - (C) 2001 Jos Visser / Mark Janssen */ -/* Contact: josv@osp.nl / maniac@maniac.nl */ +/* Proxytunnel - (C) 2001-2002 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ /* * This program is free software; you can redistribute it and/or modify @@ -19,5 +19,5 @@ #define VERSION "1.0.8" #define PACKAGE "Proxytunnel" -#define PURPOSE "Build generic tunnels through HTTPS proxys" +#define PURPOSE "Build generic tunnels through HTTPS proxies" #define AUTHORS "Jos Visser (Muppet) , Mark Janssen (Maniac) " diff --git a/proxytunnel b/proxytunnel index a7f91b0..02e4b14 100755 Binary files a/proxytunnel and b/proxytunnel differ diff --git a/proxytunnel.c b/proxytunnel.c index b194c1b..6c59d9e 100755 --- a/proxytunnel.c +++ b/proxytunnel.c @@ -1,5 +1,5 @@ -/* Proxytunnel - (C) 2001 Jos Visser / Mark Janssen */ -/* Contact: josv@osp.nl / maniac@maniac.nl */ +/* Proxytunnel - (C) 2001-2002 Jos Visser / Mark Janssen */ +/* Contact: josv@osp.nl / maniac@maniac.nl */ /* * This program is free software; you can redistribute it and/or modify @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "config.h" #include "cmdline.h" @@ -43,6 +45,9 @@ static const char base64digits[] = int sd; /* The tunnel's socket descriptor */ int read_fd=0; /* The file descriptor to read from */ int write_fd=1; /* The file destriptor to write to */ +char *program_name; /* Guess what? */ +int i_am_daemon; /* Also... */ + /* * All the command line options @@ -50,7 +55,7 @@ int write_fd=1; /* The file destriptor to write to */ struct gengetopt_args_info args_info; #define SIZE 80 -char basicauth[SIZE]; /* Buffer to hold the proxy's basic auth */ +char basicauth[SIZE]; /* Buffer to hold the proxies basic authentication data */ #define SIZE2 65536 char buf[SIZE2]; /* Data transfer buffer */ @@ -62,17 +67,46 @@ char buf[SIZE2]; /* Data transfer buffer */ #define MAX( x, y ) ( ( (x)>(y) ) ? (x) : (y) ) #endif +/* + * Give a message to the user + */ +void message( char *s, ... ) +{ + va_list ap; + char buf[1024]; + + va_start( ap, s ); + vsnprintf( buf, sizeof( buf ), s, ap ); + va_end( ap ); + + if ( i_am_daemon ) + syslog( LOG_NOTICE, buf ); + else + fputs( buf, stderr ); +} + +/* + * My own perror function (uses the internal message) + */ +void my_perror( char *msg ) +{ + char *err = strerror( errno ); + + message( "Error! %s: %s\n", msg, err ); +} /* * Kill the program (signal handler) */ -void signal_handler(int signal) { +void signal_handler( int signal ) +{ close(0); close(1); - if (sd!=0) close(sd); + if ( sd != 0 ) + close( sd ); - fprintf(stderr,"Tunnel closed on signal %d\n",signal); + message( "Tunnel closed on signal %d\n", signal ); exit(1); } @@ -130,7 +164,7 @@ void tunnel_connect() { */ if( ( sd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) { - perror("Can not create socket"); + my_perror("Can not create socket"); exit(1); } @@ -139,13 +173,13 @@ void tunnel_connect() { */ if( ! ( he = gethostbyname( args_info.proxyhost_arg ) ) ) { - perror("Proxy host not found"); + my_perror("Proxy host not found"); exit(1); } if( args_info.verbose_flag ) { - fprintf( stderr, "%s is %d.%d.%d.%d\n", + message( "%s is %d.%d.%d.%d\n", args_info.proxyhost_arg, he->h_addr[0] & 255, he->h_addr[1] & 255, @@ -166,16 +200,19 @@ void tunnel_connect() { */ if( connect( sd, (struct sockaddr*) &sa, sizeof( sa ) ) < 0 ) { - perror("connect() failed"); + my_perror("connect() failed"); exit(1); } if( ! args_info.quiet_flag ) { - fprintf( stderr, "Connected to %s:%d\n", + message( "Connected to %s:%d\n", args_info.proxyhost_arg, args_info.proxyport_arg ); } + + /* Make sure we get warned when someone hangs up on us */ + signal(SIGHUP,signal_handler); } /* @@ -201,7 +238,7 @@ void make_basicauth() if( args_info.verbose_flag ) { - fprintf( stderr, "Proxy basic auth is %s\n", basicauth ); + message( "Proxy basic auth is %s\n", basicauth ); } free( p ); @@ -225,7 +262,7 @@ void readline() { if( recv( sd, &c ,1 ,0 ) < 0) { - perror( "Socket read error" ); + my_perror( "Socket read error" ); exit( 1 ); } @@ -237,7 +274,7 @@ void readline() *p = 0; if( args_info.verbose_flag ) - fprintf( stderr, "%s", buf ); + message( "%s", buf ); } /* @@ -250,17 +287,17 @@ void analyze_HTTP() if (strcmp( p, "HTTP/1.0" ) != 0 && strcmp( p, "HTTP/1.1" ) != 0) { - fprintf(stderr,"Unsupported HTTP version number %s\n",p); - exit(1); + message( "Unsupported HTTP version number %s\n", p ); + exit( 1 ); } p = strtok( 0, " "); if( strcmp( p, "200" ) != 0 ) { - fprintf( stderr, "HTTP return code: '%s'\n", p ); + message( "HTTP return code: '%s'\n", p ); p += strlen( p ) + 1; - fprintf( stderr, "%s\n", p ); + message( "%s\n", p ); exit( 1 ); } } @@ -289,20 +326,20 @@ void proxy_protocol() if( args_info.verbose_flag ) { - fprintf( stderr, "DEBUG: ipbuf = '%s'\n", ipbuf ); - fprintf( stderr, "DEBUG: desthost = '%s'\n", + message( "DEBUG: ipbuf = '%s'\n", ipbuf ); + message( "DEBUG: desthost = '%s'\n", args_info.desthost_arg ); } args_info.desthost_arg = ipbuf; if( args_info.verbose_flag ) - fprintf( stderr, "DEBUG: desthost = '%s'\n", + message( "DEBUG: desthost = '%s'\n", args_info.desthost_arg ); } else if( args_info.verbose_flag ) - fprintf( stderr, "Can't lookup dest host: %s.\n", + message( "Can't lookup dest host: %s.\n", args_info.desthost_arg ); } @@ -328,14 +365,14 @@ void proxy_protocol() } if( args_info.verbose_flag ) - fprintf( stderr, "%s", buf); + message( "%s", buf); /* * Send the CONNECT instruction to the proxy */ if( send( sd, buf, strlen( buf ), 0 ) < 0 ) { - perror( "Socket write error" ); + my_perror( "Socket write error" ); exit( 1 ); } @@ -367,7 +404,7 @@ int copy(int from, int to) */ if ( ( n = read( from, buf, SIZE2 ) ) < 0 ) { - perror( "Socket read error" ); + my_perror( "Socket read error" ); exit( 1 ); } @@ -382,7 +419,7 @@ int copy(int from, int to) */ if ( write( to, buf, n ) != n ) { - perror( "Socket write error" ); + my_perror( "Socket write error" ); exit( 1 ); } @@ -419,7 +456,7 @@ void cpio() if( ! args_info.quiet_flag ) { - fprintf( stderr, "Starting tunnel\n" ); + message( "Starting tunnel\n" ); } /* @@ -477,7 +514,7 @@ void cpio() } else { - perror( "Exceptional condition" ); + my_perror( "Exceptional condition" ); break; } } @@ -495,15 +532,108 @@ void cpio() if( args_info.verbose_flag ) { - fprintf( stderr, "Tunnel closed\n" ); + message( "Tunnel closed\n" ); } } +/* + * Leave a goodbye message + */ +void einde() { + syslog(LOG_NOTICE,"Goodbye..."); + closelog(); +} + +/* + * Run as a standalone daemon + */ +void do_daemon() +{ + int listen_sd; + struct sockaddr_in sa_serv; + struct sockaddr_in sa_cli; + size_t client_len; + int pid = 0; + int sd_client; + char buf[80]; + unsigned char addr[4]; + + if ( ( listen_sd = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 ) + { + my_perror( "Server socket creation failed" ); + exit(1); + } + + memset( &sa_serv, '\0', sizeof( sa_serv ) ); + sa_serv.sin_family = AF_INET; + sa_serv.sin_addr.s_addr = INADDR_ANY; + sa_serv.sin_port = htons( args_info.standalone_arg ); + + if ( bind( listen_sd, (struct sockaddr * )&sa_serv, sizeof( sa_serv ) ) < 0) + { + my_perror("Server socket bind failed"); + exit(1); + } + + signal(SIGHUP,SIG_IGN); + signal(SIGCHLD,SIG_IGN); + + if ( ( pid = fork( ) ) < 0 ) + { + my_perror( "Cannot fork into the background" ); + exit( 1 ); + } + else if ( pid > 0 ) + { + message( "Forked into the background with pid %d\n", pid ); + exit(0); + } + + openlog( program_name, LOG_CONS|LOG_PID,LOG_DAEMON ); + i_am_daemon = 1; + atexit( einde ); + listen( listen_sd, 5 ); + + while (1==1) + { + sd_client = accept( listen_sd, + (struct sockaddr *)&sa_cli, &client_len ); + + if ( sd_client < 0 ) + { + syslog( LOG_ERR, "accept() failed. Bailing out..." ); + exit(1); + } + + if ( ( pid = fork() ) < 0 ) + { + syslog( LOG_ERR, "Cannot fork worker" ); + } + else if ( pid == 0 ) + { + read_fd = write_fd = sd_client; + tunnel_connect(); + proxy_protocol(); + cpio(); + exit( 0 ); + } + + memcpy( &addr, &sa_cli.sin_addr.s_addr, 4 ); + sprintf( buf, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3] ); + syslog( LOG_NOTICE, + "Started tunnel pid=%d for connection from %s", pid, buf ); + close( sd_client ); + } +} + + /* * We begin at the beginning */ int main( int argc, char *argv[] ) { + program_name = argv[0]; + /* * New and improved option handling, using GNU getopts -- Maniac */ @@ -512,6 +642,8 @@ int main( int argc, char *argv[] ) /* * This is what we do: + * - Check if we need to run as a daemon. If so, a completely + * different mainline is needed... * - Set a signal for the hangup (HUP) signal * - Optionally create the proxy basic authenticcation cookie * - Connect the sd socket to the proxy @@ -520,19 +652,31 @@ int main( int argc, char *argv[] ) */ signal( SIGHUP, signal_handler ); + if( args_info.user_given && args_info.pass_given ) { make_basicauth(); } - /* Inetd */ - if( args_info.inetd_flag ) + /* Do we need to run as a standalone daemon? */ + if ( args_info.standalone_arg > 0 ) { - write_fd=0; + /* Do processing in the other mainline... */ + do_daemon(); + } + else + { + /* Inetd trick */ + if( args_info.inetd_flag ) + { + write_fd=0; + } + + /* Main processing */ + tunnel_connect(); + proxy_protocol(); + cpio(); } - tunnel_connect(); - proxy_protocol(); - cpio(); exit( 0 ); }