Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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

  • Loading branch information...
commit a61f4989844d9101005ff7e1c97deac055b06d5c 0 parents
Peteris Krumins authored

Showing 1 changed file with 122 additions and 0 deletions. Show diff stats Hide diff stats

  1. +122 0 tcp-proxy2.pl
122 tcp-proxy2.pl
... ... @@ -0,0 +1,122 @@
  1 +#!/usr/bin/perl
  2 +#
  3 +# Peteris Krumins (peter@catonmat.net)
  4 +# http://www.catonmat.net -- good coders code, great reuse
  5 +#
  6 +#
  7 +# Written for the article "A TCP Proxy in Perl":
  8 +#
  9 +# http://catonmat.net/blog/perl-tcp-proxy
  10 +#
  11 +
  12 +use warnings;
  13 +use strict;
  14 +
  15 +use IO::Socket::INET;
  16 +use IO::Select;
  17 +
  18 +my @allowed_ips = ('all', '10.10.10.5');
  19 +my $ioset = IO::Select->new;
  20 +my %socket_map;
  21 +
  22 +my $debug = 1;
  23 +
  24 +sub new_conn {
  25 + my ($host, $port) = @_;
  26 + return IO::Socket::INET->new(
  27 + PeerAddr => $host,
  28 + PeerPort => $port
  29 + ) || die "Unable to connect to $host:$port: $!";
  30 +}
  31 +
  32 +sub new_server {
  33 + my ($host, $port) = @_;
  34 + my $server = IO::Socket::INET->new(
  35 + LocalAddr => $host,
  36 + LocalPort => $port,
  37 + ReuseAddr => 1,
  38 + Listen => 100
  39 + ) || die "Unable to listen on $host:$port: $!";
  40 +}
  41 +
  42 +sub new_connection {
  43 + my $server = shift;
  44 + my $remote_host = shift;
  45 + my $remote_port = shift;
  46 +
  47 + my $client = $server->accept;
  48 + my $client_ip = client_ip($client);
  49 +
  50 + unless (client_allowed($client)) {
  51 + print "Connection from $client_ip denied.\n" if $debug;
  52 + $client->close;
  53 + return;
  54 + }
  55 + print "Connection from $client_ip accepted.\n" if $debug;
  56 +
  57 + my $remote = new_conn($remote_host, $remote_port);
  58 + $ioset->add($client);
  59 + $ioset->add($remote);
  60 +
  61 + $socket_map{$client} = $remote;
  62 + $socket_map{$remote} = $client;
  63 +}
  64 +
  65 +sub close_connection {
  66 + my $client = shift;
  67 + my $client_ip = client_ip($client);
  68 + my $remote = $socket_map{$client};
  69 +
  70 + $ioset->remove($client);
  71 + $ioset->remove($remote);
  72 +
  73 + delete $socket_map{$client};
  74 + delete $socket_map{$remote};
  75 +
  76 + $client->close;
  77 + $remote->close;
  78 +
  79 + print "Connection from $client_ip closed.\n" if $debug;
  80 +}
  81 +
  82 +sub client_ip {
  83 + my $client = shift;
  84 + return inet_ntoa($client->sockaddr);
  85 +}
  86 +
  87 +sub client_allowed {
  88 + my $client = shift;
  89 + my $client_ip = client_ip($client);
  90 + return grep { $_ eq $client_ip || $_ eq 'all' } @allowed_ips;
  91 +}
  92 +
  93 +die "Usage: $0 <local port> <remote_host:remote_port>" unless @ARGV == 2;
  94 +
  95 +my $local_port = shift;
  96 +my ($remote_host, $remote_port) = split ':', shift();
  97 +
  98 +
  99 +print "Starting a server on 0.0.0.0:$local_port\n";
  100 +my $server = new_server('0.0.0.0', $local_port);
  101 +$ioset->add($server);
  102 +
  103 +while (1) {
  104 + for my $socket ($ioset->can_read) {
  105 + if ($socket == $server) {
  106 + new_connection($server, $remote_host, $remote_port);
  107 + }
  108 + else {
  109 + next unless exists $socket_map{$socket};
  110 + my $remote = $socket_map{$socket};
  111 + my $buffer;
  112 + my $read = $socket->sysread($buffer, 4096);
  113 + if ($read) {
  114 + $remote->syswrite($buffer);
  115 + }
  116 + else {
  117 + close_connection($socket);
  118 + }
  119 + }
  120 + }
  121 +}
  122 +

0 comments on commit a61f498

Please sign in to comment.
Something went wrong with that request. Please try again.