3 # Peteris Krumins (peter@catonmat.net)
4 # http://www.catonmat.net -- good coders code, great reuse
6 # A simple TCP proxy that implements IP-based access control
7 # Currently the ports are hard-coded, and it proxies
8 # 0.0.0.0:1080 to localhost:55555.
10 # Written for the article "Turn any Linux computer into SOCKS5
11 # proxy in one command," which can be read here:
13 # http://www.catonmat.net/blog/linux-socks5-proxy
14 # https://github.com/pkrumins/perl-tcp-proxy/raw/master/tcp-proxy.pl
19 my ($from,$to) = @ARGV;
20 die "usage: $0 localhost:9335 10.60.3.35:9100\n" unless defined $from && defined $to && $from =~ m/:/ && $to =~ m/:/;
25 my @allowed_ips; # = ('127.0.0.1'); FIXME -- disabled IP check
26 my $ioset = IO::Select->new;
32 my ($host, $port) = @_;
33 return IO::Socket::INET->new(
36 ) || die "Unable to connect to $host:$port: $!";
40 my ($host, $port) = @_;
41 my $server = IO::Socket::INET->new(
46 ) || die "Unable to listen on $host:$port: $!";
51 my $client = $server->accept;
52 my $client_ip = client_ip($client);
54 unless (client_allowed($client)) {
55 print "Connection from $client_ip denied.\n" if $debug;
59 print "Connection from $client_ip accepted.\n" if $debug;
61 my $remote = new_conn(split(/:/,$to));
65 $socket_map{$client} = $remote;
66 $socket_map{$remote} = $client;
69 sub close_connection {
71 my $client_ip = client_ip($client);
72 my $remote = $socket_map{$client};
74 $ioset->remove($client);
75 $ioset->remove($remote);
77 delete $socket_map{$client};
78 delete $socket_map{$remote};
83 print "Connection from $client_ip closed.\n" if $debug;
88 return inet_ntoa($client->sockaddr);
92 return 1 unless @allowed_ips;
94 my $client_ip = client_ip($client);
95 return grep { $_ eq $client_ip } @allowed_ips;
98 print "Starting a server on $from -> $to\n";
99 my $server = new_server(split(/:/,$from));
100 $ioset->add($server);
102 use Data::Dump qw(dump);
105 for my $socket ($ioset->can_read) {
106 if ($socket == $server) {
107 new_connection($server);
110 next unless exists $socket_map{$socket};
111 my $remote = $socket_map{$socket};
113 my $read = $socket->sysread($buffer, 4096);
115 $remote->syswrite($buffer);
116 warn "# ", inet_ntoa($socket->sockaddr), " buffer=", dump($buffer);
119 close_connection($socket);