#!/usr/bin/perl -w # -*- perl -*- # # (c) 1999 Chris Chiappa # This code is released to the public domain. I take no responsibility # for anything done with it. It is supplied without any warranty. # # V1.1 # V1.0 6/13/1999 # # $Id: stunnel,v 1.2 2000/03/07 20:21:23 griffon Exp $ # ####################################################################### # Proxy through an https tunnel. sshd probably needs to be running on # port 443 unless the proxy is very lenient. # You should add an entry to your .ssh/config such as the following: # # host remote.host.com # ProxyCommand /home/user/bin/stunnel %h %p # Port 443 # # Thereafter 'ssh remote.host.com' will use this program to tunnel # through the firewall to the remote host. # # You may need to tweak it a little to cope with the peculiarities # of your firewall. ####################################################################### use strict; use Socket; use FileHandle; #### Configuration #### my $proxy = "www-proxy.mydomain.com"; my $proxy_port = 80; ################################################################# my ($rem_host, $rem_port) = ($ARGV[0], $ARGV[1]); $| = 1; $rem_host || die "Remote host not supplied"; $rem_port || die "Remote port not supplied"; my $pSOCK = proxy_connect(); $pSOCK || die "Couldn't connect to proxy!"; my $SOCK = $$pSOCK; # These hashes hold the source and destination file handles for the # file numbers we use in select() my (%rfds, %wfds); my ($stdin_fileno, $sock_fileno) = (fileno(*STDIN), fileno($SOCK)); $rfds{$stdin_fileno} = \*STDIN; $rfds{$sock_fileno} = $SOCK; $wfds{$stdin_fileno} = $SOCK; $wfds{$sock_fileno} = \*STDOUT; $SOCK->print("CONNECT $rem_host:$rem_port HTTP/1.0\n\n"); SCANHEADERS: while(<$SOCK>) { /^\s+$/ && last SCANHEADERS; } #(! m,^HTTP/1.. 2.. Connection established,) && # die "Unexpected response from firewall: $_"; # Set up for select my $rin = ""; vec($rin, $stdin_fileno, 1) = 1; vec($rin, $sock_fileno, 1) = 1; my $ein = $rin; my ($rout, $eout); # Loop, reading from one socket and writing to the other like a good # proxy program SELECT: while(1) { my $nfound = select($rout = $rin, undef, $eout = $ein, 1024); $nfound || next SELECT; (vec($eout, $stdin_fileno, 1) || vec($eout, $sock_fileno, 1)) && last SELECT; foreach my $key (keys(%rfds)) { if(vec($rout, $key, 1)) { do_copy($rfds{$key}, $wfds{$key}) || last SELECT; } } # next SELECT; } $SOCK->close(); exit(0); ####################################################################### # Copy stuff from one filehandle to another sub do_copy { my($pIn, $pOut) = @_; my ($buf, $len, $offset, $br); $len = sysread($$pIn, $buf, 1024); $len || return 0; $offset = 0; while($len) { $br = syswrite($$pOut, $buf, $len, $offset); $br || return 0; $offset += $br; $len -= $br; } return 1; } # Connect to the proxy and return a filehandle for it. sub proxy_connect { my $iaddr = inet_aton($proxy); my $paddr = sockaddr_in($proxy_port, $iaddr); my $proto = getprotobyname('tcp'); my $fh = new FileHandle; socket($fh, PF_INET, SOCK_STREAM, $proto) or return; connect($fh, $paddr) or return; $fh->autoflush(1); return \$fh; }