This is a network architecture prototype which illustrates the way HTTP tunneling (forwarding of TCP connections) is used to handle the internet traffic. It emulates how internet clients communicate with a production server through a public-facing reverse proxy that uses HTTP tunneling to manages the connections as well as the incoming and outgoing traffic on behalf of the server.
It comes with a full, user-friendly monitoring interface and will provide useful insights on what's actually happening at the transport layer level during http or network transactions at large.
This project was designed with the goal of emulating some actual internet traffic :
- Node.js processes are used to emulate each network host :
client,proxyandserver. - Each process runs inside a dedicated Docker container with its own network interface and IP address.
- Two Docker
bridgenetworks are used as well, each with their own subnet mask and gateway:ntw-internet: emulates the internet, to which theclientcontainers are connected.ntw-local: emulates the local isolated network of a business/cloud provider, to which theservercontainer is connected.
- The
proxycontainer is connected to bothntw-internetandntw-localin order to function as a reverse proxy (thus having 2 network interfaces).
The purpose is also to illustrate the fundamentals of proxied client/server communication, so :
- At startup, the
clientprocess issues arequesttoproxyto open a proxied connection toserver. - It then waits for the request to emit the
connectevent, thus indicating that the connection is established. - From there, all communications between the
clientandserverprocesses happen by reading from and writing to the proxied connection's TCP socket. - All events occuring on the different processes are written to their respective container's logs in a user-friendly manner.
- A custom tmux session is used to visualize
client,proxyandservercontainers logs on a single screen and monitor the traffic.
The server container emulates a production server running in an isolated network.
The server process can run in two modes :
-
HTTP mode
- A Node.js
instance runs on top of the proxied connections.http.Server - Each time a valid HTTP request is received, the instance returns a valid HTTP response with code
200 (OK). - When an invalid HTTP request is received, the instance returns a valid HTTP response with code
400 (Bad Request)and closes the proxied connection.
- A Node.js
-
TCP mode
- A Node.js
instance runs on top of the proxied connections.net.Server - Each time some data is read from a connection's TCP socket, the instance echoes the received bytes.
- A Node.js
The proxy container emulates a public facing reverse proxy, running in an isolated network but also connected to the internet
- It is a Node.js
instance.http.Server - The instance establishes a connection between
clientandservercontainers when issued a HTTPCONNECTrequest. - Once connected, it returns a TCP socket (Node.js
) to thestream.Duplexclient.
Note: all traffic between client and proxy containers is secured by TLSv1.3 (a TLS layer has been added between the clients TCP sockets and the Node.js http.Server instance handling them inside the proxy). As a result, the traffic between the clients and the server that would be publicly exposed in a real world situation is encrypted.
The client container emulates a host connected to the internet, sending requests to and receiving responses from the production server through the reverse proxy
- The process uses
to issue a HTTPhttp.requestCONNECTrequest to theproxycontainer at startup. - It retrieves a TCP socket (Node.js
) once the connection tostream.Duplexserveris established. - Afterwards, it performs continuous reads from a specific named pipe using this module and write whatever bytes are read to the TCP socket (thus sending it to
server).
- Linux distro or WLS2 (debian 11 recommended)
- GNU Bash shell (version 5.1.4 recommended)
- Docker (version 20.10.16 recommended)
- Openssl (version 1.1.1 recommended)
- Tmux (version 3.1 recommended)
- Git (version 2.30.2 recommended)
Navigate to your install directory and type the following commands sequence :
git clone https://github.com/mulekick/node-http-tunnel.gitto clone the repository.cd node-http-tunnelto cd into it.. tunnel.sh tlsto configure the TLS layer by generating a certificate and a private key that will be used by theproxyprocess.. tunnel.sh buildto build the Docker images for theclient,proxyandservercontainers.
When in the node-http-tunnel directory, type one of the following commands :
-
. tunnel.sh start http- creates networks
ntw-internetandntw-local. - starts container
serverin HTTP mode (web server) and attaches it tontw-local. - starts container
proxyand attaches it tontw-localandntw-internet. - starts containers
client-1andclient-2and attaches them tontw-internet. - starts a custom tmux session displaying all the containers logs and a spare shell.
- creates networks
-
. tunnel.sh start tcp- creates networks
ntw-internetandntw-local. - starts container
serverin TCP mode (echo server) and attaches it tontw-local. - starts container
proxyand attaches it tontw-localandntw-internet. - starts containers
client-1andclient-2and attaches them tontw-internet. - starts a custom tmux session displaying all the containers logs and a spare shell.
- creates networks
Once the containers are started and the tmux session is up :
- Use tmux commands to navigate the session to the bottom window and access the spare shell.
- Type
docker exec -it client-1 /bin/bashto open a shell inside containerclient-1(orclient-2). - Once inside the container, echo or cat whatever you want into the named pipe
/src/client-pipeto have the client send it to the server through the proxied connection. - See the traffic taking place at the TCP socket level between the
clientandservercontainers. - Once you're done, type
exitorCtrl-Dto exit the container and return to the spare shell.
Note: dont forget that your proxied connection will be terminated if you send anything that is not a valid HTTP message when the server container runs in HTTP mode. Some sample well-formatted HTTP messages are provided in /HTTPMSGS, cat these into /src/client-pipe to have the server respond with nice Pepe the Frog ASCII art.
When in the node-http-tunnel directory (in the spare shell or elsewhere), type the following command:
. tunnel.sh stop- stops and removes containers
client-1,client-2,serverandproxy(thus terminating all network connections) - removes networks
ntw-internetandntw-local - kills the tmux session (thus terminating all foreground processes)
- stops and removes containers
- Basic knowledge of the bash/sh shell commands (at least
cd,echoandcat) is required. - Basic knowledge of tmux navigation commands (C-b up, down, etc ...) is required.
- Reminder : IETF defined that line endings for HTTP messages must be CRLF. The Node.js HTTP parser won't have it if you do otherwise.
- What is HTTP tunneling.
- In the event you need an npm module which exports Pepe the Frog ASCII art.
- The next step in this project should probably be to setup a firewall inside the
proxycontainer to block irrelevant/malicious connection attempts. I may do it later using iptables.