2021-12-16
In today’s post we will be talking about Gender Changing. Huh? Gender Changing? Is this still a programming blog? Yes, it is. We’ll be looking at TCP Gender Changer today along with a simple Socat based implementation of it.
You have a server running inside a zone protected by a firewall that needs to be accessed by clients from outside the firewall. The server must run inside the protected zone and it cannot directly accept inbound connections from outside. This is a common situation for non-public facing sensitive systems such as those used by Finance companies for accepting connections from other companies.
One of the solutions to this problem is a mechanism known as TCP Gender Changer. You can read about it in more detail on Wikipedia but the basic idea is to have a process inside the Firewall initiating connections to another process outside the Firewall and also to the Server. The process outside the Firewall is responsible for accepting inbound client connections and then relaying them to outbound connections it received from the other process inside the Firewall. I know it’s a bit confusing so let’s break down the mechanism into steps.
We can implement a simple TCP Gender Changer using the Socat utility for Unix based systems. Quoting from the Socat manual, Socat is a command line based utility that establishes two bidirectional byte streams and transfers data between them.
To setup the LL Node, we use the following command to start a Socat process.
$ socat -d -d -d tcp-l:8000,reuseaddr,fork tcp-l:8001,reuseaddrThe command above tells Socat to first listen for client connections
on port 8000 and then on port 8001. Port 8000 is for external clients
whereas port 8001 is for the CC Node. The fork option when
listening on port 8000 will make Socat spawn a new child
process for listening on port 8001 each time it accepts a
connection from external client on port 8000. This way we
will be able to handle an arbitrary number of clients.
We start a CC Node using the following Socat command. Here we assume that the server is listening for connections on port 7200.
$ socat -d -d -d tcp:<LL-node-address>:8001,forever,interval=2,fork tcp:<server-address>:7200This command tells socat to first establish a connection to the LL Node on port 8001 and then establish a connection to the server on port 7200.
Since, the LL Node is configured to accept a client connection before listening for a connection from the CC Node, connection attempts from CC Node to LL Node will fail until the latter receives a client connection. For this reason we tell the CC Node Socat to retry connection attempts to LL Node forever with a sensible interval between attempts (2 seconds in the example above). Only when a connection attempt to LL Node succeeds will the CC Node connect to the Server.
Let’s test if the above setup works as expected. For simplicity of our test we wil run both LL and CC nodes as well as the server locally.
Server
For the server I am going to use the default Python HTTP Server from
http.server module. This server serves static files in the
current directory.
$ python3 -m http.server 7200LL Node
$ socat -d -d -d tcp-l:8000,reuseaddr,fork tcp-l:8001,reuseaddrCC Node
$ socat -d -d -d tcp:127.0.0.1:8001,forever,interval=2,fork tcp:127.0.0.1:7200Now, if you open localhost:8000 in your web browser you
will see the HTTP Server return a result containing all the files in its
current directory.