Persistent and reliable TCP tunneling based on asyncio
.
To illustrate the two differenc modes Client can operate in, we give a detailed example of two conceptually different setups.
Let's suppose you have an application server listening on host
srv:6789
, you have two servers host1
and host2
and a client
workstation cli
. Let's suppose we have the following setup:
cli
---> host1
---> host2
---> srv
The arrow a
---> b
indicates that a
can connect to b
, but
b
can not connect to a
.
In this case you start a tunnel server on host2
that listens on port 9000.
Server('0.0.0.0', 9000)
You also strart a tunnel client
on host1
in CONNECT
mode with the following parameters
Client(
aiowstunnel.CONNECT, # you need connect mode here
'host2', 9000, # the tunnel server is listening on port 9000
'0.0.0.0', 5678, # the listening host/port
'srv', 6789, # the connectiong host/port
)
In this case, the parameters mean the following:
server_mode
- This was set to
aiowstunnel.CONNECT
, which means the client wants the server to use theconnect_host
,connect_port
settings when a new connection is received by the client and connect to the given host-port. tunnel_host
,tunnel_port
- It tells the Client where the tunnel server is listening. The client will connect to this server and tries to keep the connection open.
listen_host
,listen_port
- The
server_mode
parameter isCONNECT
, so the server is going to use theconnect_host
andconnect_port
parameters and the client will listen on this host/port. In this example the client is running onhost1
and it will start a new server on0.0.0.0:5678
. The program running oncli
can connect to this server as if it was the application server connect_host
,connect_port
- As described earlier in
CONNECT
mode the server will use these to connect when a connection comes to the client. The client tells the server to connect tosrv:6789
-- the application server.
What if the firewall is configured in this way:
cli
---> host1
<--- host2
---> srv
In this case the tunnel server will be started on host1
, the
client on host2
. The server needs to listen 0.0.0.0:5678
while
the client connects to the application server.
Server('0.0.0.0', 9000)
Client(
aiowstunnel.LISTEN, # you need the server to listen
'host1', 9000, # the tunnel server is listening on port 9000
'0.0.0.0', 5678, # the server listens here
'srv', 6789, # the client connects here
)
Here is the code to properly start the server in the above example
import asyncio
import signal
import logging
from aiowstunnel.server import Server
logging.basicConfig(level=logging.INFO)
async def serve(stop):
srv = Server('0.0.0.0', 9000)
srv.start()
await stop
await srv.close()
loop = asyncio.get_event_loop()
# install signal handler
stop = asyncio.Future()
loop.add_signal_handler(signal.SIGINT, stop.set_result, None)
loop.run_until_complete(serve(stop))
Starting the client is very similar
import asyncio
import logging
import signal
from aiowstunnel.client import Client
import aiowstunnel
logging.basicConfig(level=logging.INFO)
async def provide_tunnel(stop):
cli = Client(
aiowstunnel.LISTEN, # you need the server to listen
'host1', 9000, # the tunnel server is listening on port 9000
'0.0.0.0', 5678, # the server listens here
'srv', 6789, # the client connects here
)
cli.start()
await stop
await cli.close()
loop = asyncio.get_event_loop()
# install signal handler
stop = asyncio.Future()
loop.add_signal_handler(signal.SIGINT, stop.set_result, None)
loop.run_until_complete(provide_tunnel(stop))
TODO