socksproxy.pl
Dieses Perl Script binded auf eine lokale IP, Port und dient als Proxy ueber einen Socks5 Proxy. Es werden die Perl-Module: Conifg::General und IO::Socket::Socks verwendet, also notfalls nachinstallieren. Diese beiden Module gibt es definitv bei CPAN, wenn ihr sie z.B. nicht in eurer Portscollection findet. Fuer den Fall, dass ihr die Module bei CPAN rausladet, entpackt sie danach lokal in euerem Filesystem (z.B. unter /tmp) und wechselt in das Verzeichnis. Falls ihr keine Lust habt, dass die Module unter dem standard PERL_LIB Pfad instaliert werden, so erstellt ein Verzeichnis fuer euere selbstgebauten CPAN Module (z.B. /usr/opt/cpan) und baut das Makefile mit perl Makefile.PL PREFIX=/mein/pfad/zu/eigenen/cpan/modulen. Danach ein make und anschliessend ein make install. Nun muesst ihr den zusaetzlichen PERL_LIB Pfad noch im Script verewigen. Tragt hierzu use lib "/mein/pfad/zu/eigenen/cpan/modulen"; in dem Script oberhalb der use myNewCPANModul; ein.
Hier der Code
sockproxy.rc
# our sockproxy.rc configfile # # max connections pool = 1 # local server localaddr = localhost localport = 2222 # remote socks socksaddr = socksport = # loglevel loglevel = 1
socksproxy.pl
#-----------------------------------------------------------------------------
# "THE BEER-WARE LICENSE" (Revision 42):
# <benny@pilgerer.org> wrote this file. As long as you retain this notice you
# can do whatever you want with this stuff. If we meet some day, and you think
# this stuff is worth it, you can buy me a beer in return.
#-----------------------------------------------------------------------------
use strict;
# some config stuff
use Getopt::Std;
use Config::General;
# our socket stuff
use IO::Select;
use IO::Socket;
use IO::Socket::Socks;
# forward declaration
sub read_config();
sub usage();
sub log_it($$);
sub check_host($$);
sub set_server();
sub set_socks();
sub close_me($$$$);
# usage ?
if(!$ARGV[0] || !$ARGV[1]) {
usage();
}
# cmd line options
my (%opts);
getopts('c:p:s:v', \%opts);
# suck my config
my($config);
$config = read_config();
$config->{"loglevel"} = 2 if($opts{"v"} && $config->{"loglevel"} < 2);
$config->{"logstruct"} = { "ERROR" => 1, "INFO" => 2, "DEBUG" => 3 };
$config->{"remaddr"} = $ARGV[0];
$config->{"remport"} = $ARGV[1];
$config->{"localaddr"} = $opts{"s"} if($opts{"s"});
$config->{"localport"} = $opts{"p"} if($opts{"p"});
# check input
check_host($config->{"remaddr"}, $config->{"remport"});
check_host($config->{"localaddr"}, $config->{"localport"});
check_host($config->{"socksaddr"}, $config->{"socksport"});
# start server
my ($sel, $lsn);
($lsn, $sel) = set_server();
# loop IO Socket
my($client, $pool, $socks, $buffer, $sbuffer, @queue);
while(@queue = $sel->can_read) {
foreach my $fh (@queue) {
if($fh == $lsn) {
# accept client
$client = $lsn->accept;
# add to IO
$sel->add($client);
log_it("INFO", "client ".$client->peerhost().":".
$client->peerport()." connected");
# start socks
$socks = set_socks();
# add client to socks IO
$sel->add($socks);
# assign to pool
$config->{"pool"} --;
$pool->{"c"}{"$client"} = $socks;
$pool->{"s"}{"$socks"} = $client;
# exit if too much connecions
if($config->{"pool"} < 0) {
close_me(3, $sel, $client, $socks);
} else {
log_it("INFO", "remaining clients to handle ".
$config->{"pool"});
}
} elsif($pool->{"c"}{"$fh"}) {
$fh->recv($buffer, 4096);
log_it("DEBUG", "CLIENT -> $0: $buffer");
if(!$buffer) {
close_me(1, $sel, $fh, $pool->{"c"}{"$fh"});
} else {
$pool->{"c"}{"$fh"}->send($buffer);
log_it("DEBUG", "$0 -> SOCKS: $buffer");
}
} elsif($pool->{"s"}{"$fh"}) {
$fh->recv($sbuffer, 4096);
log_it("DEBUG", "SOCKS -> $0: $sbuffer");
if(!$sbuffer) {
close_me(2, $sel, $pool->{"s"}{"$fh"}, $fh);
} else {
$pool->{"s"}{"$fh"}->send($sbuffer);
log_it("DEBUG", "$0 -> CLIENT: $sbuffer");
}
}
}
}
# end
die("NOTREACHED!");
sub close_me($$$$) {
my($val, $sel, $client, $socks) = @_;
for($val) {
if(/^1$/) {
log_it("INFO", "closing client ".$client->peerhost().":".
$client->peerport()." connection");
}
if(/^2$/) {
log_it("INFO", "closing socks connection");
}
if(/^3$/) {
$client->send("too much connections, sorry");
log_it("INFO", "too much connections");
}
$sel->remove($client);
$client->close;
$sel->remove($socks);
$socks->close;
$config->{"pool"} ++;
}
return();
}
sub set_socks() {
shift;
my $socks = new IO::Socket::Socks( ProxyAddr => $config->{"socksaddr"},
ProxyPort => $config->{"socksport"},
ConnectAddr => $config->{"remaddr"},
ConnectPort => $config->{"remport"} );
log_it("INFO", "socks connect init");
return($socks);
}
sub set_server() {
shift;
my($lsn, $sel);
$lsn = new IO::Socket::INET(Listen => 1,
LocalAddr => $config->{"localaddr"},
LocalPort => $config->{"localport"},
Reuse => 1);
if(!ref($lsn)) {
log_it("ERROR", "Can not bind to ".$config->{"localaddr"}.":".
$config->{"localport"}.".");
exit(1);
}
$sel = new IO::Select($lsn);
log_it("INFO", "server started on ".$config->{"localaddr"}.":".
$config->{"localport"});
return($lsn, $sel);
}
sub usage () {
print <<EOF;
Usage: $0 [-cpsv] <hostname/ip port>
-c config file
-p bind to port
-s bind to ipaddress
-v verbose
EOF
exit(0);
}
sub check_host ($$) {
my($host, $port) = @_;
my($addr, @addr);
if(!(@addr = gethostbyname($host)) && !is_ip($host)) {
log_it("ERROR", "unknown hostname or ip $host.");
exit(1);
};
if(!$port || $port !~ /^\d+$/ || $port < 1 || $port > 65535) {
log_it("ERROR", "illegal port $port.");
exit(1);
}
log_it("INFO", "checked host $host and port $port");
return;
}
sub is_ip ($) {
my $ip = shift;
my $c = 0;
for(split/\./, $ip) {
return 0 if(!length($_) or /\D/);
return 0 if($_ < 0 or $_ > 255);
$c++;
}
return 1;
}
sub log_it ($$) {
my ($level, $text) = @_;
if($config->{"loglevel"} >= $config->{"logstruct"}{"$level"} ||
$level eq "ERROR") {
printf("%s\n", $text);
}
return;
}
sub read_config() {
my($config, $conf);
$conf = new Config::General(-ConfigFile => ($opts{"c"}) ? $opts{"c"} :
$ENV{"HOME"}."/.socksd/socksd.conf");
%{ $config } = $conf->getall;
return $config;
}