-
Notifications
You must be signed in to change notification settings - Fork 16
/
tcp-proxy2.pl
executable file
·122 lines (98 loc) · 2.74 KB
/
tcp-proxy2.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/perl
#
# Peteris Krumins ([email protected])
# 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);
}
}
}
}