Tunnel
Peer-to-peer, secure, TCP/UDP port forwarding using HTTP(s) relay for NAT/firewall traversal
Install / Use
/learn @SomajitDey/TunnelREADME
Tunnel
Secure, multiplexed, TCP/UDP port forwarder using piping-server by @nwtgck as relay. Designed mainly for p2p connections between peers behind (multiple) NAT/firewalls.
Features
- TCP/UDP tunnel between peers, each of which may be behind (multiple) NAT(s), i.e. unreachable from the public internet.
- Firewalls don't cause problems as only outgoing http(s) connections are used.
- Security: To connect, peers must know the unique ID of the serving peer and a shared secret key. Traffic between peer and relay is encrypted (TLS). Relay doesn't store anything.
- Multiplexing: Each tunnel supports multiple concurrent connections. Connections are full-duplex.
- Many-to-One: The forwarding peer acts as the client and the forwardee peer acts as the server. Server can support multiple clients at any given time. Each node can act as both server and client.
- Resilience: Peers auto-reconnect in the face of intermittent connectivity.
- No superuser privilege required.
- Option to host your own relay server (easily and for free).
- KISS: Just a single, small, portable, shell-script.
- Built in installer and updater.
Command-line
For the special case of IPFS, see #examples below.
<u>ID</u>: Every node is given a unique (base64) ID -
tunnel -i
ID is bound to hardware (MAC address) and the environment variables USER, HOME and HOSTNAME. Share it with your peers once and for all. Note: two users on the same machine are given separate node-IDs because their USER and HOME variables differ.
<u>Server mode</u>: Expose your local port to peers with whom you share any secret string -
tunnel [options] [-u] [-k <shared-secret>] <local-port>
<u>Client mode</u>: Forward your local port to peer's exposed local port -
tunnel [options] [-u] [-k <shared-secret>] [-b <local-port>] [-I <IP>] <peer-ID:peer-port>
If no local-port is provided using the -b option, tunnel uses a random unused port. The port used, is always reported at stdout.
The -I option is handy when client is running on a laptop that occasionally gets connected to the LAN the server is on. When server can be found on LAN with private IP = <IP>, tunnel connects through LAN.
Client and server must use the same secret to be able to connect with each other. The secret string may also be passed using the environment variable TUNNEL_KEY. Secret passed with -k takes precedence.
-u flag denotes use of UDP instead of the default TCP. If used, it must be used by both the peers.
All logs are at stderr by default. With the -l <logfile> option, however, one can launch tunnel in background (<u>daemon mode</u>) with logs dumped at <logfile>. The daemon process ID is shown to the user during launch so that he can kill the daemon anytime with
tunnel -K <procID>
<u>Options</u>:
For a full list of options see : tunnel -h
Installation and Updating
Download with:
curl -LO https://raw.githubusercontent.com/SomajitDey/tunnel/main/tunnel
Make it executable:
chmod +rx ./tunnel
Then install system-wide with:
./tunnel -c install
If you don't have sudo privilege, you can install locally instead:
./tunnel -c install -l
To update anytime after installation:
tunnel -c update
Dependency/Portability
This program is simply an executable bash script depending on standard GNU tools including socat, openssl, curl, mktemp, cut, awk, sed , flock, pkill, dd, xxd, base64 etc. that are readily available on standard Linux distros.
If your system lacks any of these tools, and you do not have the sudo privilege required to install it from the native package repository (e.g. sudo apt-get install <package>), try downloading a portable binary and install it locally at ${HOME}/.bin.
Examples
<u>SSH</u>:
Peer A exposes local SSH port -
tunnel -k "${secret}" 22
Peer B connects -
tunnel -b 67868 -k "${secret}" -l /dev/null "${peerA_ID}:22" # Daemon due to -l
ssh -l "${login_name}" -p 67868 localhost
<u>IPFS</u>:
Let peer A has IPFS-peer-ID: 12orQmAlphanumeric. Her IPFS daemon listens at default TCP port 4001. She exposes it with -
tunnel -k "${swarm_key}" ipfs
swarm_key is just any secret string peer A may use to control who can swarm connect to her using tunnel.
Peer B now connects with peer A for file-sharing or pubsub or p2p -
tunnel -k "${swarm_key}" 12orQmAlphanumeric
This last command swarm connects to peer A through the piping-server relay and keeps on swarm connecting every few seconds in the background to keep the connection alive.
tunnel starts the IPFS daemon in background if not already active.
The path to IPFS repo may be passed with the option -r. Otherwise, the environment variable IPFS_PATH or the default path ~/.ipfs is used as usual. Example: tunnel -r ~/.ipfs -i gives the IPFS peer ID.
<u>Remote Shell</u>:
Suppose you would regularly need to launch commands at your workplace Linux box from your home machine. And you don't want to / can't use SSH over tunnel for some reason.
At the workplace computer, expose some random local TCP port, e.g. 49090 and connect a shell to that port:
tunnel -l "/tmp/tunnel.log" -k "your secret" 49090 # Note the base64 node id emitted
socat TCP-LISTEN:49090,reuseaddr,fork SYSTEM:'bash 2>&1'
Back at your home:
tunnel -l "/dev/null" -b 5000 -k "your secret" "node_id_of_workplace:49090"
rlwrap nc localhost 5000
Using rlwrap is not a necessity. But it sure makes the experience sweeter as it uses GNU Readline and remembers the input history (accessible with the up/down arrow keys similar to your local bash sessions).
<u>Redis</u>:
Need to connect to a remote Redis instance hosted by a peer or yourself? At the remote host, expose the TCP port that redis-server runs on (default: 6379), with tunnel.
At your local machine, use tunnel to forward a TCP port to the remote port. Point your redis-cli at the forwarded local port.
Applications
Below are some random use-cases I could think of for tunnel. Broadly speaking, anything that involves NAT/firewall traversal (e.g. WebRTC without TURN) or joining a remote LAN, should find tunnel useful. Some of the following ideas are rather sketchy, haven't been tested at all, and may not work, but nonetheless are documented here, at least for the time being, just for the sake of inspiration. If you found any of these useful, or useless, or you have found entirely new applications for tunnel, please post at discussions. Those cases that I have tested are labelled as "working".
- Connecting to IPFS peers (Working).
- P2P chatting, mailing, VoIP, streaming, gaming, screen-sharing, file-sharing, gambling, troubleshooting and what not.
- Connecting IOT devices.
- Connecting your workstation with your home-computer or laptop with SSH (Working), RDP or VNC.
- Shell-shovelling (Working).
- Beat your firewall with a self-hosted or peer-provided VPN.
- Joining intranet office chats (over office LAN) from your home across the internet. For example, BeeBEEP and LAN Messenger may use a local port that has been forwarded to from a node inside your office using
tunnel. - P2P (serverless) audio/video. For example, forward a local TCP/UDP port to peer's localhost and point your p2p client to it. Ready-made FOSS: Jami, Jitsi, Toxchat and Retroshare.
- Serverless remote-control using Teamviewer or Anydesk. Forward a local port, say 6000, to peer's local TCP port 5938 (for TV) and 7070 (for Anydesk) and use 127.0.0.1:6000 as the IP:port tuple of the peer.
- Making a local (web) port publicly accessible, a.k.a reverse-proxy accessible from the internet: Simply run
tunnelat Heroku (for free) and forward the port stored in the environment variablePORTto your local port that you want to expose. And you have your public URL as: https://your-app-name.herokuapp.com. - Accessing feed from a remote IP webcam using a universal network camera adapter: Forward a local port to a remote node that can access the mobile cam over [WLAN](https://en.wikipedia.org/wiki/Wireless_LAN
