上次说的Perl代码供大家参考
功能:把远端的应用服务端口通过HTTPS代理服务器映射成本地端口。这对于那些不支持HTTPS代理的TCP应用还有点儿小用处! :D
#!/usr/bin/env perl
#
# Use remote HTTPS PROXY to tunnel the remote service to local!
# Author: Yi Zhao
# Blog: linuxyz.blogspot.com
#
# Based on original "ssltunnel.pl" by Alex Hornby <alex@hornby.org.uk>
# $Id: ssltunnel.pl,v 1.17 2003/06/10 14:54:16 alex Exp $
#
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
package httpsproxy;
use strict;
my $VERSION=1.0;
use IO::File;
use IO::Select;
use IO::Socket;
use Net::SSL;
use Getopt::Long;
use MIME::Base64;
my %options = (
proxyport=>443,
reproxyport=>8080,
localaddr=>"127.0.0.1",
localport=>8080,
);
sub usage
{
print STDERR <<EOF;
usage: perl httpsproxy.pl [options] [remote-host:port]
Tunnels a TCP/IP connection through an http proxy using SSL.
WARNING: Only use this if you have the proxy administrator\'s permission
WARNING: The authors of this package offer no warranty
options:
--help This help
--proxyhost 1.2.3.4 Mandatory proxy host port (default 443)
--proxyport 443 Optional proxy host port (default 443)
--proxyuser <username> Optional proxy user name
--proxypasswd pass Optional proxy pass word
--useragent agent Optional user agent name
--reproxyhost 1.2.3.4 Optional intermediate http proxy host
--reproxyport 123 Optional intermediate http proxy host port (default 8080)
--reproxyuser <username> Optional intermediate http proxy user name
--reproxypasswd pass Optional intermediate http proxy pass word
--localaddr 1.2.3.4 Optional local addr to listen on (default 127.0.0.1)
--localport 123 Optional local port to listen on (default 8080)
e.g. To run a local http proxy to the remote HTTPS proxy
./httpsproxy.pl --proxyhost 10.1.1.80 \
--proxyport 443 --localport 80 www.abc.com:80
EOF
exit(1);
}
# Parse command line arguments
sub parseArgs
{
GetOptions(\%options, qw/dumpfile=s
proxyhost=s proxyport=i proxyuser=s proxypasswd=s useragent=s
reproxyhost=s reproxyport=i reproxyuser=s reproxypasswd=s reuseragent=s
localaddr=s localport=i
debug! help!
log-file=s pidfile=s/);
if ( $options{help} ) {
usage();
}
for (@ARGV) {
if (m/^([^:]*):(.*)$/) {
$options{desthost} = $1;
$options{destport} = int($2) || getservbyname($2, 'tcp') || die "unknown port";
print "Mapping $options{desthost}:$options{destport} as $options{localaddr}:$options{localport}\n";
}
}
if ( !defined($options{proxyhost}) ) {
print STDERR "error: You must give a proxyhost\n";
usage();
}
}
# This is really inefficient, but we only use it for reading the proxy response
# so that does not really matter.
sub xgetline($)
{
my $proxy = shift;
my $val="";
my $buf;
do {
$proxy->read($buf, 1);
$val .= $buf;
} until ($buf eq "\n");
$val;
}
sub httpProxy
{
my ( $proxy, $desthost, $destport, $proxyuser, $proxypasswd ) = @_;
# Force flushing of socket buffers
# The actual connect
$proxy->print("CONNECT " . $desthost . ":" .
$destport . " HTTP/1.0\r\n");
if ( $options{debug} ) {
print STDERR "CONNECT " . $desthost . ":" .
$destport . " HTTP/1.0\n";
}
# Basic auth if needed
if ( $proxyuser ) {
my $auth = encode_base64(
$proxyuser . ":" . $proxypasswd);
$proxy->print("Proxy-authorization: Basic $auth\r\n");
if ( $options{debug} ) {
print STDERR "Proxy-authorization: Basic $auth"
}
}
# User agent name if needed
if ( $options{useragent} ) {
$proxy->print("User-Agent: " . $options{useragent} . "\r\n");
if ( $options{debug} ) {
print STDERR "User-Agent: " . $options{useragent} . "\n";
}
}
# end of headers
$proxy->print("\r\n");
my $status;
# Wait for HTTP status code, bail out if you don't get back a 2xx code.
#$_ = $proxy->getline();
#$_ = $proxy->getchunk();
$_ = xgetline($proxy);
next if /^[\r]*$/;
($status) = (split())[1];
die("Received a bad status code \"$status\" from proxy server\n$_")
if ( int($status/100) != 2 );
while($_ = xgetline($proxy)) {
chomp; # Strip <LF>
last if /^[\r]*$/; # Empty line or a single <CR> left
if ( $options{debug} ) {
print STDERR "Got extra data [$_]\n";
}
}
return $status;
}
sub connectProxy
{
if ( $options{reproxyhost} ) {
# proxy support
$ENV{HTTPS_PROXY} = qq(http://$options{reproxyhost}:$options{reproxyport});
# proxy_basic_auth
$ENV{HTTPS_PROXY_USERNAME} = $options{reproxyuser} if $options{reproxyuser};
$ENV{HTTPS_PROXY_PASSWORD} = $options{reproxypass} if $options{reproxypass};
}
# debugging (SSL diagnostics)
$ENV{HTTPS_DEBUG} = $options{debug} ? 1 : 0;
my $proxy = new Net::SSL (
PeerAddr => $options{proxyhost},
PeerPort => $options{proxyport},
Proto => 'tcp',
);
die "Error connecting to proxy host $options{proxyhost} " .
"port $options{proxyport}: $!\n" unless $proxy;
# Force flushing of socket buffers
$proxy->autoflush(1);
# only if the remote host are speficied
httpProxy($proxy, $options{desthost}, $options{destport},
$options{proxyuser}, $options{proxypasswd} )
if ( $options{desthost} );
return $proxy;
}
sub connectLocal
{
my $listen = new IO::Socket::INET (
Listen=> 5,
LocalAddr => $options{localaddr},
LocalPort => $options{localport},
Proto => 'tcp',
Reuse => 1,
);
die "can't listen on " . $options{localaddr} . ":"
. $options{localport} unless $listen;
print STDERR "Accepting network clients on " .
$options{localaddr} . ":" .$options{localport} . "\n";
my %client2proxy;
my %proxy2client;
my $s = IO::Select->new();
$s->add($listen);
my $dumpfh;
if ( $options{dumpfile} ) {
$dumpfh = new IO::File($options{dumpfile}, "w")
or die "could not open dump file $_";
$dumpfh->autoflush(1);
}
while ( 1 ) {
my @res = IO::Select::select($s, undef, undef, 3600);
if ( @res == 0 ) {
print STDERR "got select error\n";
last;
}
my ($read, $write, $error) = @res;
# Check for disconnect
for my $fh ( @$error ) {
print STDERR "socket $fh is in error\n";
$s->remove($fh);
exit();
}
# Process handles ready to read;
for my $fh ( @$read ) {
if ( $fh == $listen ) {
my $client = $listen->accept();
$client->autoflush(1);
$s->add($client);
my $proxy = connectProxy();
$s->add($proxy);
print STDERR "New connection from " . $client->peerhost() . "\n";
$client2proxy{$client} = $proxy;
$proxy2client{$proxy} = $client;
} else {
my $destfh;
my $isclient = 0;
if ( exists( $client2proxy{$fh} ) ) {
$destfh = $client2proxy{$fh};
$isclient = 1;
} elsif ( exists( $proxy2client{$fh} ) ) {
$destfh = $proxy2client{$fh};
}
my $num = sysread($fh, $_, 4096);
if ( $num) {
syswrite($destfh, $_, $num);
# Optional dump of traffic
if ( $dumpfh ) {
if ($isclient) {
$dumpfh->print("client[$_]\n");
} else {
$dumpfh->print("proxy[$_]\n");
}
}
} else {
$s->remove($fh);
$s->remove($destfh);
if ( $isclient ) {
print STDERR "client disconnected\n";
delete($client2proxy{$fh});
delete($proxy2client{$destfh});
} else {
print STDERR "proxy disconnected\n";
delete($client2proxy{$destfh});
delete($proxy2client{$fh});
}
close($fh);
close($destfh);
if(%proxy2client == 0 ) {
print STDERR "last client disconnected\n";
}
}
}
}
}
}
parseArgs();
connectLocal();
0;
__END__
没有评论:
发表评论