#!/usr/local/bin/perl
#
# ssh-tunnel.pl	
#
# Usage: ssh-tunnel.pl ssl-proxy port destination_host port
#
# This script can be used by ssh as a "ProxyCommand" to 
# traverse a www-proxy/firewall that supports the http CONNECT 
# command described in
# http://home.netscape.com/newsref/std/tunneling_ssl.html
#
# Example, connect to host named "remote" outside of your firewall:
#
# $ ssh remote -o'ProxyCommand ssh-tunnel.pl www-proxy 80 remote 22'
#
# Better yet, insert the ProxyCommand definition for host "remote" in 
# your $HOME/.ssh/config file:
#
#      .
#      .
#    Host remote
#      ProxyCommand /usr/local/bin/ssh-tunnel.pl www-proxy 80 %h %p
#      .
#      .
#
# Written by Urban Kaveus <urban@statt.ericsson.se>

require 'sys/socket.ph';

# Parse command line arguments

if ( $#ARGV != 3 ) {
    print STDERR "Usage: $0 ssl-proxy port destination port\n";
    print STDERR $#ARGV, "\n";
    exit(1);
}

$sslproxy    = shift;
$proxyport   = shift;
$destination = shift;
$destport    = shift;

# Set up network communication

($protocol) = (getprotobyname("tcp"))[2];
($proxyip)  = (gethostbyname($sslproxy))[4];
$localaddr  = pack('S n a4 x8', &AF_INET, 0, "\0\0\0\0");
$proxyaddr  = pack('S n a4 x8', &AF_INET, $proxyport, $proxyip);

socket (PROXY, &AF_INET, &SOCK_STREAM, $protocol) or
    die("Failed to create cocket");
bind (PROXY, $localaddr) or
    die("Failed to bind socket");
connect (PROXY, $proxyaddr) or
    die("Failed to connect to $sslproxy port $proxyport");

# Force flushing of socket buffers

select (PROXY);  $| = 1; 
select (STDOUT); $| = 1;

# Send a "CONNECT" command to proxy:

print PROXY "CONNECT $destination:$destport HTTP/1.0\r\n\r\n";

# Wait for HTTP status code, bail out if you don't get back a 2xx code.

$_ = <PROXY>;
($status) = (split())[1];

die("Received a bad status code \"$status\" from proxy server") 
    if ( int($status/100) != 2 );

# Skip through remaining part of MIME header

while(<PROXY>) {
    chomp;   # Strip <LF>
    last if /^[\r]*$/;		# Empty line or a single <CR> left
}

# Start copying packets in both directions.

if($child = fork) { # Parent process
    while (sysread(STDIN,$_,4096)) {
        print PROXY;
    }
    sleep 2;
    kill(15,$child) if $child;
}

else { # Child process
    while (sysread(PROXY,$_,4096)) {
        print STDOUT;
    }
}



