From: Dobrica Pavlinusic Date: Mon, 11 Mar 2019 06:48:50 +0000 (+0100) Subject: https://github.com/pkrumins/perl-tcp-proxy/raw/master/tcp-proxy.pl X-Git-Url: http://git.rot13.org/?p=safeq;a=commitdiff_plain;h=1e10a6b88aef7e5301fdb37622bba23486ab5b04 https://github.com/pkrumins/perl-tcp-proxy/raw/master/tcp-proxy.pl --- diff --git a/tcp-proxy.pl b/tcp-proxy.pl new file mode 100755 index 0000000..3d5ebe8 --- /dev/null +++ b/tcp-proxy.pl @@ -0,0 +1,117 @@ +#!/usr/bin/perl +# +# Peteris Krumins (peter@catonmat.net) +# http://www.catonmat.net -- good coders code, great reuse +# +# A simple TCP proxy that implements IP-based access control +# Currently the ports are hard-coded, and it proxies +# 0.0.0.0:1080 to localhost:55555. +# +# Written for the article "Turn any Linux computer into SOCKS5 +# proxy in one command," which can be read here: +# +# http://www.catonmat.net/blog/linux-socks5-proxy +# + +use warnings; +use strict; + +use IO::Socket; +use IO::Select; + +my @allowed_ips = ('1.2.3.4', '5.6.7.8', '127.0.0.1', '192.168.1.2'); +my $ioset = IO::Select->new; +my %socket_map; + +my $debug = 1; + +sub new_conn { + my ($host, $port) = @_; + return IO::Socket::INET->new( + PeerAddr => $host, + PeerPort => $port + ) || die "Unable to connect to $host:$port: $!"; +} + +sub new_server { + my ($host, $port) = @_; + my $server = IO::Socket::INET->new( + LocalAddr => $host, + LocalPort => $port, + ReuseAddr => 1, + Listen => 100 + ) || die "Unable to listen on $host:$port: $!"; +} + +sub new_connection { + my $server = shift; + my $client = $server->accept; + my $client_ip = client_ip($client); + + unless (client_allowed($client)) { + print "Connection from $client_ip denied.\n" if $debug; + $client->close; + return; + } + print "Connection from $client_ip accepted.\n" if $debug; + + my $remote = new_conn('localhost', 55555); + $ioset->add($client); + $ioset->add($remote); + + $socket_map{$client} = $remote; + $socket_map{$remote} = $client; +} + +sub close_connection { + my $client = shift; + my $client_ip = client_ip($client); + my $remote = $socket_map{$client}; + + $ioset->remove($client); + $ioset->remove($remote); + + delete $socket_map{$client}; + delete $socket_map{$remote}; + + $client->close; + $remote->close; + + print "Connection from $client_ip closed.\n" if $debug; +} + +sub client_ip { + my $client = shift; + return inet_ntoa($client->sockaddr); +} + +sub client_allowed { + my $client = shift; + my $client_ip = client_ip($client); + return grep { $_ eq $client_ip } @allowed_ips; +} + +print "Starting a server on 0.0.0.0:1080\n"; +my $server = new_server('0.0.0.0', 1080); +$ioset->add($server); + +while (1) { + for my $socket ($ioset->can_read) { + if ($socket == $server) { + new_connection($server); + } + else { + next unless exists $socket_map{$socket}; + my $remote = $socket_map{$socket}; + my $buffer; + my $read = $socket->sysread($buffer, 4096); + if ($read) { + $remote->syswrite($buffer); + } + else { + close_connection($socket); + } + } + } +} +