Permalink
Browse files

usage: tcp-proxy2.pl <local port> <host:port>

  • Loading branch information...
0 parents commit a61f4989844d9101005ff7e1c97deac055b06d5c @pkrumins committed Mar 31, 2011
Showing with 122 additions and 0 deletions.
  1. +122 −0 tcp-proxy2.pl
@@ -0,0 +1,122 @@
+#!/usr/bin/perl
+#
+# Peteris Krumins (peter@catonmat.net)
+# http://www.catonmat.net -- good coders code, great reuse
+#
+#
+# Written for the article "A TCP Proxy in Perl":
+#
+# http://catonmat.net/blog/perl-tcp-proxy
+#
+
+use warnings;
+use strict;
+
+use IO::Socket::INET;
+use IO::Select;
+
+my @allowed_ips = ('all', '10.10.10.5');
+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 $remote_host = shift;
+ my $remote_port = 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($remote_host, $remote_port);
+ $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 || $_ eq 'all' } @allowed_ips;
+}
+
+die "Usage: $0 <local port> <remote_host:remote_port>" unless @ARGV == 2;
+
+my $local_port = shift;
+my ($remote_host, $remote_port) = split ':', shift();
+
+
+print "Starting a server on 0.0.0.0:$local_port\n";
+my $server = new_server('0.0.0.0', $local_port);
+$ioset->add($server);
+
+while (1) {
+ for my $socket ($ioset->can_read) {
+ if ($socket == $server) {
+ new_connection($server, $remote_host, $remote_port);
+ }
+ 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);
+ }
+ }
+ }
+}
+

0 comments on commit a61f498

Please sign in to comment.