#!/usr/bin/perl #use strict; use IO::Socket; use IO::Select; $progname = $0; $progname =~ s,.*[/\\],,; # use basename only $progname =~ s/\.\w*$//; # strip extension, if any $VERSION = sprintf("%d.%02d", q$Revision: 1.0 $ =~ /(\d+)\.(\d+)/); ($lPort, $proxyStr, $remoteStr) = @ARGV; unless (defined($proxyStr) and defined($remoteStr)) { print "use: localProxy [] : ". ":\n"; my $DISTNAME = 'findProxy ' . $VERSION; die <<"EOT"; This is findProxy $VERSION ($DISTNAME) Author: wayne\@nym.alias.net This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. EOT }; ($proxyAddr, $proxyPort) = split(/:/, $proxyStr); ($host, $port) = split(/:/, $remoteStr); $port=($port or 8080); #default to port 80 if not specified $type='CONNECT'; # make this more general later $murdered=0; $makeNewConnection=1; $firstTime=1; $protocol = getprotobyname("tcp"); while ($makeNewConnection and !$murdered) { #make the daemon (this may not be necessary inside this loop) #but it gets closed often $lPort=10000 + $port; socket(INC, PF_INET, SOCK_STREAM, $protocol) || die "socket:$!"; setsockopt (INC, SOL_SOCKET, SO_REUSEADDR, pack ("l", 1)) || die "setsockopt:$!"; bind(INC,sockaddr_in($lPort,INADDR_ANY)) || die "bind: $!"; if ($firstTime) {print STDOUT "connect to localhost port $lPort now\n"; $firstTime=0}; listen(INC,10) || die "listen:$!"; #allows 10 connections at a time #(5 is the default), #drops through here on #the first one accept(OUT,INC) || die "accept:$!"; #accept 1 connection only for now #I need to handle this better, #it *should* be easy, we don't do #much on each connection! $fhin = $fhout = \*OUT; &makeConnection(); #connect to the proxy # hot buffers everywhere foreach ( \*PROXY, $fhin, $fhout, STDOUT ) { select($_); $|=1 }; # Send command to proxy: print PROXY "$type $host:$port HTTP/1.1\r\n"; #change \r\n to #$CRLF for Macs #HTTP/1.1 ok too. print PROXY "Host: $host\r\n"; #not necessary, even for HTTP/1.1 print PROXY "Content-Length: 0\r\n"; #not necessary print PROXY "\r\n"; # Wait for HTTP status code, die if you don't get a 2xx code. ($status) = (split(/\s+/,))[1]; die "failed to CONNECT to $host:$port" unless ($status); die "bad response code CONNECTING to $host:$port" unless ( int($status/100) == 2 ); # Skip through remaining part of HTTP header (until blank line) while () { last if ( /^[\r\n]+$/ ); }; #connected through to remote server #now relay packets $s = IO::Select->new($fhin,\*PROXY); $makeNewConnection=0; while ( ! $makeNewConnection and !$murdered) { foreach $fh ( $s->can_read(10) ) { #0 indicates end of input, but sometimes it's undefined (?) if (!($num = sysread($fh,$_,4096)) or $murdered) { $s->remove($fh); close $fh; $s->remove($fhin); close $fhin; $makeNewConnection=1; #reopen all the sockets etc. #a web proxy will be closing the connection #after each GET/POST. }; if ($num) {syswrite( ((fileno($fh)==fileno($fhin)) ?PROXY :$fhout),$_,$num)}; } }; # while (!makenewConnection }; # while (run and makeNewConnection) 1; sub makeConnection{ # connect to proxy server ... socket (PROXY, PF_INET, SOCK_STREAM, $protocol) or die("Failed to create socket:$!"); connect (PROXY, sockaddr_in($proxyPort,inet_aton($proxyAddr))) or # die("Failed to connect to $proxyAddr port $proxyPort: $!"); do {print "Failed to connect to $proxyAddr port $proxyPort\n"; print "it's either dead, or your access is blocked\n"; exit}; select(\*PROXY); $|=1; #make it hot }; sub signal_handler { $murdered=1; #we've been killed; must have done something wrong };