Monday, August 13, 2012

ForwardMachine - dynamic port forwarding

While working on implementing direct access to instances on Shelly Cloud (for `shelly console`, uploading files, etc.), we needed a solution for dynamic port forwarding from the Internet to our internal network.

There are a few options available. One could set up static map of forwarded ports. However, that is unfeasible when the number of destinations is too big, or when the destination can change dynamically. Another possible solution would be using ProxyMachine, which is a great tool that allows you to route traffic based on the data on application level. But, that doesn't work with encrypted protocols like SSH.

Because of that, we created our own solution - ForwardMachine. It is a simple tool for configuring port forwarding dynamically. It's written in Ruby using EventMachine. It forwards incoming TCP traffic on a port taken from given range to a destination host and port. Let's see how it works.

First we install forwardmachine gem.
$ gem install forwardmachine
When we have it installed let's start the server from the command line.
$ forwardmachine --forwarder-host proxy.example.com --ports-range 8000..9000
  • --forwarder-host - sets host from which ports will be forwarded to given destination
  • --ports-range - sets ports range which will be used for setting up port forwards
Port forwards are configured by sending simple commands to a TCP server which by default listens on localhost port 8899. ForwardMachine requires that destination hosts are reachable from proxy.example.com host.

Let's say we want to access a host internal1.example.com via SSH which is inside our internal network. We need to send to ForwardMachine destination in the format "host:port",  so for our example it will be "internal1.example.com:22".

In the below example we will use nc, but basically you can use any other TCP client.
We connect to the control server
$ nc localhost 8899
We type destination host and port
internal1.example.com:22
As response we get host and port where we need to connect to reach internal1.example.com:22
proxy.example.com:8000
The port will stay open as long as a client is connected to it. After the client disconnects, the forwarded port is closed and released back to the ports pool.

Here is an init.d script for running ForwardMachine as a daemon using start-stop-daemon. Also, make sure to check out the code on GitHub.  

No comments:

Post a Comment