Skip to content

Instantly share code, notes, and snippets.

@caHarkness
Last active May 23, 2022 16:03
Show Gist options
  • Save caHarkness/f30a064416292b9c686258f856ec5aaa to your computer and use it in GitHub Desktop.
Save caHarkness/f30a064416292b9c686258f856ec5aaa to your computer and use it in GitHub Desktop.
port-forwarding
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);
}
}
}
}
#! /bin/sh
### BEGIN INIT INFO
# Provides: port-forwarding
# Required-Start: $local_fs $network $named $time $syslog
# Required-Stop: $local_fs $network $named $time $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: Simple TCP port forwarding in Debian
### END INIT INFO
#
# To install this, run as root:
# export SERVICE_NAME="port-forwarding"; curl "https://gist.githubusercontent.com/caHarkness/f30a064416292b9c686258f856ec5aaa/raw/port-forwarding" > /etc/init.d/$SERVICE_NAME; chmod +x /etc/init.d/$SERVICE_NAME; ln -s /etc/init.d/$SERVICE_NAME /etc/rc2.d/S99$SERVICE_NAME; nano /etc/init.d/$SERVICE_NAME; sleep 3; systemctl daemon-reload
#
WORKING_DIRECTORY="/opt/port-forwarding"
forward_port () {
LISTEN_PORT="$1"
DESTINATION="$2"
PERL_SCRIPT=$(curl -k "https://gist.githubusercontent.com/caHarkness/f30a064416292b9c686258f856ec5aaa/raw/forward.pl")
perl -e "$PERL_SCRIPT" "$LISTEN_PORT" "$DESTINATION" &
PERL_PROCESS="$!"
touch $WORKING_DIRECTORY/pids/$PERL_PROCESS
echo $DESTINATION > $WORKING_DIRECTORY/ports/$LISTEN_PORT
}
start_forwarding () {
mkdir $WORKING_DIRECTORY
mkdir $WORKING_DIRECTORY/pids
mkdir $WORKING_DIRECTORY/ports
forward_port 54303 192.168.1.10:54303
}
list_forwarded_ports () {
for i in "$WORKING_DIRECTORY/ports/"*
do
PORT=$(basename $i)
DEST=$(< $i)
echo "$PORT $DEST"
done
}
stop_forwarding () {
for i in "$WORKING_DIRECTORY/pids/"*
do
KPID=$(basename $i)
kill $KPID
done
for i in "$WORKING_DIRECTORY/ports/"*
do
rm "$i"
done
}
edit_service () {
SERVICE_NAME=$(basename $0)
nano /etc/init.d/$SERVICE_NAME
sleep 3
systemctl daemon-reload
}
uninstall_service () {
SERVICE_NAME=$(basename $0)
rm /etc/init.d/$SERVICE_NAME
rm /etc/rc2.d/S99$SERVICE_NAME
echo "Service uninstalled."
}
PATH=/sbin:/usr/sbin:/bin:/usr/bin
. /lib/lsb/init-functions
case "$1" in
start)
start_forwarding
;;
stop)
stop_forwarding
;;
restart)
stop_forwarding
sleep 3
start_forwarding
;;
list)
list_forwarded_ports
;;
edit)
edit_service
;;
uninstall)
uninstall_service
;;
*)
echo "Usage: $0 {start|stop|restart|list|edit|uninstall}"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment