Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- #Socks Proxy Server
- ##############################################################################
- #
- # This script is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Library General Public
- # License as published by the Free Software Foundation; either
- # version 2 of the License, or (at your option) any later version.
- #
- # This script is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # Library General Public License for more details.
- #
- # You should have received a copy of the GNU Library General Public
- # License along with this library; if not, write to the
- # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- # Boston, MA 02111-1307, USA.
- #
- # Copyright (C) 2005 Emmanuel Elango.
- #
- ##############################################################################
- BEGIN {
- require Errno;
- import Errno qw(EWOULDBLOCK EINPROGRESS);
- }
- use Socket;
- use IO::Socket;
- use IO::Select;
- use IO::Socket::Socks;
- use FileHandle;
- use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
- #############################################
- #############################################
- # User configurable parameters
- #
- #Set the proxy hostname or ip below.
- $hostname = '0.0.0.0';
- #
- #Set the proxy port below.
- $hostport = '1186';
- #
- #Set the socks user id below. It is recommended to change the defaults below to prevent misuse of your proxy server.
- #Please note that the username and password are sent in clear text and can be easily sniffed on a network. For greater
- #security you could allow only certain hosts to connect by modifiying the IO::Socket::Socks module. A modified module
- #is available in the same directory as this script. Instructions are in the modifed module.
- $socksuser = 'foo';
- #
- #Set the password below.
- $socksuserpass = 'bar';
- #
- ###############################################
- ###############################################
- #sub timeout();
- #daemonize?
- # $pid = fork(); #
- # if ($pid != 0) #
- # { #
- # close (); #
- # exit(); #
- # } #
- # else #
- # { #
- $SIG{PIPE} = 'IGNORE';
- #$SIG{ALRM} = \&timeout;
- $server = IO::Socket::Socks->new( ProxyAddr=> $hostname,
- ProxyPort=> $hostport,
- Listen=>1,
- UserAuth=>\&auth,
- RequireAuth=>1,
- ) or die "Unable to bind server socket $!\n";
- if ($^O =~ m/Win32/)
- {
- my $temp = 1;
- #ioctl($server, 0x8004667E, \$temp);
- }
- else
- {
- if ($flags = fcntl($server, F_GETFL, 0)<0)
- {
- die "Unable to get server socket flags\n";
- }
- if (($flags = fcntl($server, F_SETFL, $flags | O_NONBLOCK)) < 0)
- {
- die "Unable to set server socket to at non-block\n";
- }
- }
- $readable = IO::Select->new();
- $writable = IO::Select->new();
- $readable ->add($server);
- #print "Server ID $server \n";
- while (1)
- { #print "Entering Select\n";
- if (defined (($sockets_read, $sockets_write) = IO::Select->select($readable,$writable,undef)))
- {
- #print "Select returned\n";
- #$pause = <STDIN>;
- #print $sockets_read[0]->[0];
- foreach $sock (@$sockets_read)
- {
- #print "Got a socket to work on $sock\n";
- if ($sock == $server)
- {
- #print "Detected Server Socket Read\n";
- #alarm 5;
- eval {$client = $server->accept();};
- if ($@) {print "$@\n";}
- if ($@) {next;}
- if(defined($client))
- {
- if ($^O =~ m/Win32/)
- {
- my $temp = 1;
- #ioctl($client, 0x8004667E, \$temp);
- }
- else
- {
- if ($flags = fcntl($client, F_GETFL, 0)<0)
- {
- print "Unable to get client socket flags\n";
- close($client);
- next;
- }
- if (($flags = fcntl($client, F_SETFL, $flags | O_NONBLOCK))<0)
- {
- print "Unable to set client socket to non-block\n";
- close($client);
- next;
- }
- }
- #print "$client Accepted \n";
- #alarm 0;
- $client->autoflush(1);
- $command = $client->command();
- #printf "Command = %x", $command->[0], "\n";
- if ($command->[0] == 1)
- {
- #print "Command: ",$command->[0]," Host: ",$command->[1], " Port: ", $command->[2],"\n";
- if (!($remote = IO::Socket::INET->new()))
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at IO::Socket create Error: $@\n";
- close($client);
- next;
- }
- $proto = getprotobyname('tcp');
- $remote->socket(AF_INET, SOCK_STREAM, $proto);
- if ($^O =~ m/Win32/)
- {
- my $temp = 1;
- #ioctl($remote, 0x8004667E, \$temp);
- }
- else
- {
- if ($flags = fcntl($remote, F_GETFL, 0)<0)
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at get flags\n";
- close($client);
- next;
- }
- if (($flags = fcntl($remote, F_SETFL, $flags | O_NONBLOCK))<0)
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at non-block\n";
- close($client);
- next;
- }
- }
- if (!($iaddr = inet_aton($command->[1])))
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at inet_aton\n";
- close($client);
- next;
- }
- if (!($sockaddr = sockaddr_in($command->[2], $iaddr)))
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at sockaddr_in\n";
- close($client);
- next;
- }
- if ($remote->connect($sockaddr))
- {
- $hash{$client}= $remote;
- $hash{$remote}= $client;
- #$port = $remote->sockport();
- #print "Peerhost = ",$remote->peerhost(),"Port = " ,$remote->peerport(),"\n";
- $client->command_reply(0,$remote->sockhost(),$remote->sockport());#$remote->sockhost(), $remote->sockport());
- #print "Sent reply at CONNECT\n";
- $readable->add($client);
- $readable->add($remote);
- $remote->autoflush(1);
- }
- elsif ($! == EWOULDBLOCK or $! == EINPROGRESS)
- {
- $writable->add($remote);
- $connectpending{$client} = $remote;
- $connectpending{$remote} = $client;
- }
- else
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at CONNECT\n";
- close($client);
- next;
- }
- }
- elsif ($command->[0]==2)
- {
- print "BIND detected\n";
- print "Command 1 = ", $command->[0]," Command 2 = ", inet_ntoa(inet_aton($command->[1]))," Command 3 = ", $command->[2],"\n";
- if ($command->[2] < 1024) { $port = 0;} else {$port = $command->[2];}
- print "$port\n";
- $remote = IO::Socket::INET->new(Listen => 1,
- LocalAddr => '202.41.106.14',
- LocalPort => $port,
- Proto => 'tcp',
- Blocking =>0,
- Reuse => 1);
- if($remote)
- {
- $hash{$client}= $remote;
- $hash{$remote}= $client;
- $client->command_reply(0, $remote->sockhost(), $remote->sockport());
- print $remote->sockhost(), $remote->sockport(),"\n";
- #print "Sent reply at BIND\n";
- $readable->add($client);
- $readable->add($remote);
- $servers{$remote} = $client;
- #$servers{$client} = $remote;
- $commands{$client} = $command->[1];
- }
- else
- {
- $client->command_reply(4,undef,undef);
- print "Sent error at BIND\n";
- close($client);
- }
- }
- elsif ($command->[0]==3)
- {
- if ($command->[2] < 1024) { $port = 0;} else {$port = $command->[2];}
- (exists $udpinuse1{$port}) ? $port = 0:$port;
- $udp = IO::Socket::INET->new(
- LocalPort => $port,
- LocalAddr => '202.41.106.14',
- Proto => 'udp',
- Blocking =>0,
- Reuse => 1);
- if (!$udp)
- {
- $client->command_reply(1,undef,undef);
- print "Sent reply error at new UDP server socket $!\n";
- $client->command_reply(1,undef,undef);
- close($client);
- next;
- }
- if ($^O =~ m/Win32/)
- {
- my $temp = 1;
- #ioctl($udp, 0x8004667E, \$temp);
- }
- else
- {
- if ($flags = fcntl($udp, F_GETFL, 0)<0)
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at get flags\n";
- close($client);
- next;
- }
- if (($flags = fcntl($udp, F_SETFL, $flags | O_NONBLOCK))<0)
- {
- $client->command_reply(1,undef,undef);
- #print "Sent reply error at non-block\n";
- close($client);
- next;
- }
- }
- $udpassociate{$client} = $udp;
- $udpservers{$udp} = $client;
- $command->[1] ? $udpadd{$udp} = $command->[1]:$udpadd{$udp} = $client->peerhost();
- $udpport{$udp} = $command->[2];
- $client->command_reply(0,$udp->sockhost(), $udp->sockport());
- $port = $udp->sockport();
- $readable->add($udp);
- $readable->add($client);
- $udpinuse1{$port} = $client;
- $udpinuse2{$client} = $port;
- print STDOUT "UDP Server setup Host: ", $udp->sockhost()," Port: ", $udp->sockport(),"\n";
- print STDOUT "UDP Server client Host: ", $udpadd{$udp}," Port: ", $udpport{$udp},"\n";
- }
- else
- {
- $client->command_reply(7,undef,undef); #Command not supported
- close($client);
- }
- }
- else
- {
- #alarm 0;
- print "Socks Accept failed Error: $! \n";
- }
- }
- elsif (exists ($servers{$sock}))
- {
- print "Detected incoming to BIND\n";
- if (defined ($remoteserver = $sock->accept()))
- {
- if ((inet_aton($commands{$servers{$sock}})) eq (inet_aton($remoteserver->peeraddr())))
- {
- $servers{$sock}->command_reply(0,$sock->peeraddr(),$sock->peerport());
- $hash{$remoteserver} = $servers{$sock};
- $hash{$servers{$sock}} = $remoteserver;
- delete $servers{$servers{$sock}};
- delete $commands{$servers{$sock}};
- delete $hash{$sock};
- delete $servers{$sock};
- #print "Sent reply at BIND CONNECT\n";
- $readable->remove($sock);
- close($sock);
- $readable->add($remoteserver);
- $readable->add($hash{$remoteserver});
- }
- else
- {
- $servers{$sock}->command_reply(1,undef,undef);
- #print "Sent error at BIND CONNECT bad IP\n";
- $readable->remove($sock);
- close($sock);
- close($servers{$sock});
- delete $servers{$hash{$sock}};
- delete $servers{$sock};
- delete $commands{$hash{$sock}};
- delete $hash{$hash{$sock}};
- delete $hash{$sock};
- }
- }
- else
- {
- $servers{$sock}->command_reply(1,undef,undef);
- #print "Sent error at BIND CONNECT \n";
- $readable->remove($sock);
- close($sock);
- close($servers{$sock});
- delete $servers{$hash{$sock}};
- delete $servers{$sock};
- delete $commands{$servers{$sock}};
- delete $hash{$hash{$sock}};
- delete $hash{$sock};
- }
- }
- elsif (exists ($udpassociate{$sock}))
- {
- print "Control socket read detected\n";
- $bytesread = sysread($sock,$databuf, 102400,0);
- if((!defined($bytesread )) or ($bytesread == 0))
- {
- print "Control socket close detected\n";
- $readable->remove($sock);
- $readable->remove($udpassociate{$sock});
- close($sock);
- close($udpassociate{$sock});
- delete ($udpport{$udpassociate{$sock}});
- delete ($udpadd{$udpassociate{$sock}});
- delete $udpinuse1{$udpinuse2{$sock}};
- delete $udpinuse2{$sock};
- delete ($udpservers{$udpassociate{$sock}});
- delete ($udpassociate{$sock});
- }
- }
- elsif (exists ($udpservers{$sock}))
- {
- $paddr = recv($sock,$databuf, 102400,0);
- #print STDOUT "Reached UDP1\n";
- if((defined($paddr)))
- {
- #print STDOUT "Reached UDP2\n";
- ($port, $ipaddr) = sockaddr_in($paddr);
- #$port = $sock->peerport();
- #$ipaddr = $sock->peerhost();
- #print STDOUT "From: ",inet_ntoa($ipaddr), " $port\n";
- if (($udpadd{$sock} eq inet_ntoa($ipaddr)) and ($udpport{$sock} == $port))
- {
- #print STDOUT "Detected local auth access UDP\n";
- if (ord((substr($databuf,2,1))) != 0)
- {
- next;
- }
- if(ord((substr($databuf,3,1))) == 1)
- {
- #print "UDP IP given\n";
- $udpremoteip = substr($databuf,4,4);
- $udpremoteport = unpack("n",substr($databuf,8,2));
- #($udpremoteport == 9) ? $udpremoteport = 11 : $udpremoteport;
- $data = substr($databuf,10,length($databuf) - 10);
- #print "To: ", inet_ntoa($udpremoteip), " $udpremoteport\n";
- }
- elsif (ord((substr($databuf,3,1))) == 3)
- {
- #print "UDP ADD given\n";
- $chars = ord((substr($databuf,4,1)));
- $udpremoteadd = substr($databuf,5,$chars);
- $udpremoteip = gethostbyname ($udpremoteadd);
- $udpremoteport = unpack("n",substr($databuf,4+$chars,2));
- $data = substr($databuf,6+$chars,(length($databuf) - (6+$chars)));
- #print $udpremoteadd, " $udpremoteport\n";
- }
- else
- {
- next;
- }
- $portaddr = sockaddr_in($udpremoteport, $udpremoteip);
- if (send($sock, $data, 0, $portaddr) != length($data))
- {
- print STDOUT "Remote UDP Send error $!\n";
- }
- }
- else
- {
- #print STDOUT "Detected remote incoming access UDP\n";
- $portaddr = sockaddr_in($udpport{$sock}, inet_aton($udpadd{$sock}));
- if (!(send($sock,chr(0).chr(0).chr(0).chr(1). $ipaddr.pack("n",$port).$databuf, 0, $portaddr) ))
- {
- print STDOUT "Local UDP Send error\n $!";
- }
- }
- }
- }
- else
- { #print "Detected read on normal socket $sock\n";
- if (length($data{$sock})>32768)
- {
- #print "Read paused. Buffers full on $sock\n";
- $readpaused{$sock} = 1;
- $readable->remove($sock);
- next;
- }
- $bytesread = sysread($sock,$databuf, 102400,0);
- #print "Bytes read = $bytesread from Socket $sock \n";#Buffer = $databuf MOTE \n";
- if(!defined($bytesread ))
- {
- #print "Error occured in READ. Closing socket. $sock \n";
- #$sock->flush();
- #$hash{$sock}->flush();
- if (exists ($hash{$sock}))
- {
- $readable->remove($sock);
- #print "Removed first readable socket\n";
- $readable->remove($hash{$sock});
- #print "Removed second readable socket\n";
- $writable->remove($sock);
- #print "Removed first readable socket\n";
- close ($sock);
- delete($data{$hash{$sock}});
- if (!(length($data{$sock})))
- {
- $writable->remove($hash{$sock});
- #print "Removed second readable socket $hash{$sock}. Cleaning up in READ error\n";
- #close($sock);
- close($hash{$sock});
- delete($data{$hash{$sock}});
- delete($data{$sock});
- #delete($hash{$hash{$sock}});
- delete($hash{$sock});
- delete($readpaused{$sock});
- }
- if (exists($servers{$hash{$sock}}))
- {
- delete $servers{$hash{$sock}};
- delete $commands{$sock};
- }
- }
- }
- elsif (($bytesread == 0))
- {
- #print "Socket closed in READ. Closing socket $sock.\n";
- if (exists ($hash{$sock}))
- {
- $readable->remove($sock);
- $readable->remove($hash{$sock});
- $writable->remove($sock);
- close($sock);
- delete($data{$hash{$sock}});
- if (!(length($data{$sock})))
- {
- #print "Removed second writable socket $hash{$sock}. Cleaning up in READ close\n";
- $writable->remove($hash{$sock});
- #print "Removed second readable socket\n";
- #close($sock);
- close($hash{$sock});
- delete($data{$hash{$sock}});
- delete($data{$sock});
- #delete($hash{$hash{$sock}});
- delete($hash{$sock});
- delete($readpaused{$sock});
- }
- if (exists ($servers{$hash{$sock}}))
- {
- delete $servers{$hash{$sock}};
- delete $commands{$sock};
- }
- }
- }
- else
- {
- if (exists ($hash{$sock}))
- {
- $data{$sock}.=$databuf;
- $bytessent= syswrite($hash{$sock},$data{$sock},length($data{$sock}),0);
- if(!defined($bytessent))
- {
- if ( !(($! == EWOULDBLOCK) or ($! == EAGAIN)))
- {
- #print "Error occured in READ-WRITE. Closing socket $hash{$sock}\n";
- if (defined ($hash{$sock}))
- {
- $readable->remove($sock);
- $readable->remove($hash{$sock});
- $writable->remove($hash{$sock});
- close ($hash{$sock});
- delete($data{$sock});
- if (!(length($data{$hash{$sock}})))
- {
- #print "Removed first writable socket $sock. Cleaning up in READ-WRITE close\n";
- $writable->remove($sock);
- #close($hash{$sock});
- close($sock);
- delete($data{$hash{$sock}});
- #delete($data{$sock});
- delete($hash{$hash{$sock}});
- delete($hash{$sock});
- delete($readpaused{$sock});
- }
- }
- }
- else
- {
- #print "EWOULDBLOCK on ", $hash{$sock},"\n";
- $hash{$sock}->flush();
- $writable->add($hash{$sock});
- }
- }
- elsif ($bytessent < length($data{$sock}))
- {
- #print "Partial Bytes sent = $bytessent to Socket $hash{$sock} in READ\n";
- $hash{$sock}->flush();
- $writable->add($hash{$sock});
- substr($data{$sock}, 0, $bytessent) = '';
- }
- else
- {
- #print "Complete Bytes sent = $bytessent to Socket $hash{$sock} in READ\n";
- $hash{$sock}->flush();
- $writable->remove($hash{$sock});
- substr($data{$sock}, 0, $bytessent) = '';
- }
- #print "Buffer Length = ", length($data{$sock});
- }
- }
- }
- }
- foreach $sock (@$sockets_write)
- { #print "Entered write section on $sock \n";
- if (exists $connectpending{$sock})
- {
- if ($sock->peername())
- {
- #print "Delayed connect success in WRITE\n";
- $hash{$sock}= $connectpending{$sock};
- $hash{$connectpending{$sock}}= $sock;
- #$port = $remote->sockport();
- #print "Peerhost = ",$sock->peerhost()," Port = " ,$sock->peerport(),"\n";
- $hash{$sock}->command_reply(0, $sock->sockhost(),$sock->sockport());#$hash{$sock}->sockhost(), $hash{$sock}->sockport());
- #print "Sent CONNECT reply in WRITE\n";
- $readable->add($sock);
- $readable->add($hash{$sock});
- $writable->remove($sock);
- $sock->autoflush(1);
- delete $connectpending{$connectpending{$sock}};
- delete $connectpending{$sock};
- }
- else
- {
- #print "Delayed connect failed in WRITE\n";
- $connectpending{$sock}->command_reply(1,undef,undef);
- #print "Sent CONNECT reply error in WRITE\n";
- $writable->remove($sock);
- close($sock);
- close($connectpending{$sock});
- delete $connectpending{$connectpending{$sock}};
- delete $connectpending{$sock};
- }
- }
- elsif ((length($data{$hash{$sock}}))>0)
- {
- #print "Whew I have something to write to $sock;-)\n";
- $bytessent= syswrite($sock,$data{$hash{$sock}},length($data{$hash{$sock}}),0);
- if(!defined($bytessent))
- {
- if (!(($! != EWOULDBLOCK) or ($! != EAGAIN)))
- {
- #print "Error occured on $sock in WRITE\n";
- if (defined ($hash{$sock}))
- {
- $writable->remove($sock) if $writable->exists($sock);
- $readable->remove($sock) if $readable->exists($sock);
- $readable->remove($hash{$sock}) if $readable->exists($hash{$sock});
- close($sock);
- delete($data{$hash{$sock}});
- if (!(length($data{$hash{$sock}})))
- {
- $writable->remove($hash{$sock}) if $writable->exists($hash{$sock});
- #print "Removing first writable socket $hash{$sock}. Cleaning up in WRITE error.\n";
- close($hash{$sock});
- #close($sock);
- #delete($data{$hash{$sock}});
- delete($data{$sock});
- delete($hash{$hash{$sock}});
- delete($hash{$sock});
- delete($readpaused{$sock});
- }
- }
- }
- else
- {
- #print "In write section EWOULDBLOCK on ", $sock,"\n";
- #$sock->flush();
- }
- }
- elsif ($bytessent == length($data{$hash{$sock}}))
- {
- #print "Complete Bytes sent = $bytessent to $sock in WRITE\n";
- $writable->remove($sock);
- substr($data{$hash{$sock}}, 0, $bytessent) = '';
- }
- else
- {
- #print "Partial Bytes send = $bytessent to $sock in WRITE\n";
- substr($data{$hash{$sock}}, 0, $bytessent) = '';
- }
- #print "Sent $bytessent bytes to $sock Buffer length now = ", length($data{$hash{$sock}}),"\n";
- if ((length($data{$hash{$sock}}) < 32768) and ($readpaused{$hash{$sock}}))
- {
- #print "Buffers cleared. Reading renabled on $hash{$sock}\n";
- $readpaused{$hash{$sock}} = 0;
- $readable->add($hash{$sock});
- }
- if ((length($data{$hash{$sock}}) == 0) and (!($readable->exists($hash{$sock}))))
- {
- #print "Removing first writable socket $hash{$sock}. Cleaning up in WRITE data all sent.\n";
- $writable->remove($sock) if $readable->exists($sock);
- close($hash{$sock});
- close($sock);
- delete($data{$hash{$sock}});
- delete($data{$sock});
- delete($hash{$hash{$sock}});
- delete($hash{$sock});
- delete($readpaused{$sock});
- }
- }
- #else
- #{
- # $writable->remove($sock);
- #}
- }
- }
- }
- sub auth
- {
- my $user = shift;
- my $pass = shift;
- #print "user($user) pass($pass)\n";
- return 1 if (($user eq $socksuser) && ($pass eq $socksuserpass));
- #return 1;
- }
- #sub timeout()
- #{
- # print "Alarm went off\n";
- # ($package, $filename, $line) = caller;
- # print $package,"\n", $filename,"\n", $line,"\n";
- # if ($package eq "IO::Socket::Socks")
- # {
- # print 'Closing $self', $package::self,"\n";
- #
- # close ($self);
- #exit;
- # return undef;
- # }
- # exit;
- #}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement