Skip to content
Newer
Older
100755 123 lines (98 sloc) 2.74 KB
a61f498 @pkrumins usage: tcp-proxy2.pl <local port> <host:port>
authored
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
Something went wrong with that request. Please try again.