Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for "reverse" forwarding (server listening on local) #6

Open
cipriancraciun opened this issue Oct 16, 2021 · 16 comments
Open
Milestone

Comments

@cipriancraciun
Copy link

At the moment onetun supports forwarding outbound connections (from local client to remote server).

It would be especially useful for developers to also have the reverse, namely inbound connections (from remote clients to local servers).

Based on your description on how it uses smoltun it seems to be a matter of implementing the reverse logic for the TCP forwarding.

@aramperes
Copy link
Owner

aramperes commented Oct 16, 2021

Thanks for the suggestion!

Assuming this is similar to reverse SSH tunnelling, this would only work if a onetun-compatible daemon was running on the remote server. Specifically, it would need to open a port on the remote server, which isn't possible without having a process running on the remote server in the first place.

SSH reverse-tunnelling works because sshd (daemon) can open ports on the remote server on demand, after being instructed to do so by the client (ssh) using a special request.

I have no plans for a onetund at the moment since it goes against the idea of onetun being useful in non-root/daemon-less environments. I would also need to design a protocol for onetun to instruct onetund to open a port forward.

I might change my mind down the line if I see some interest in it, or if I find a use for it myself.

@cipriancraciun
Copy link
Author

this would only work if a onetun-compatible daemon was running on the remote server.

On the contrary, one wouldn't need onetun on the remote server.

Let me expand upon how I think this could work:

  • assume that there is a Wireguard router running somewhere on the internet; (it might even be on that server;)
  • assume that if a client were to run a Wireguard client, it would be able to "join" the Wireguard server, and thus reachable (via Wireguard) on the "private IP"; (the "private IP" is onetun's source IP on the arguments;)
  • thus (again if one would use a plain Wireguard client) any process running on the local machine (if bound on the 0.0.0.0 IP) would be reachable from any other Wireguard client (or even from the internet if the Wireguard router handles the DNAT;)
  • now, how about replacing the generic wireguard client with onetun; all of a sudden if one would send a packet (in our case TCP SYN) to the "source IP", it would reach onetun;
  • however at the moment onetun just ignores any packets that are not related to the (outbound) TCP/IP connections it has initiated;

What I'm proposing is that onetun reacts to the inbound TCP/IP connections and forwards them to the local computer (in the reverse way).

Currently onetun allows the following (here "remote TCP endpoint" is any IP reachable via the Wireguard router):

local TCP client -> connect to local TCP endpoint -> [onetun TCP stack] -> [wireguard] -> ... -> server TCP listen on remote endpoint

What I'm proposing is the reverse (here the "remote endpoint" is the Wireguard IP address of the onetun client):

local TCP server <- listens on local TCP port <- [onetun TCP stack] <- [wireguard] <- ... <- client TCP connect to remote TCP endpoint

If the current command is this:

./onetun 127.0.0.1:8080 192.168.4.2:8080                                  \
    --endpoint-addr 140.30.3.182:51820                                    \
    --endpoint-public-key 'PUB_****************************************'  \
    --private-key 'PRIV_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'          \
    --source-peer-ip 192.168.4.3                                          \
    --keep-alive 10

The command line for the reverse would be:

./onetun 127.0.0.1:8080 192.168.4.3:8080                                  \
    --reverse \
    --endpoint-addr 140.30.3.182:51820                                    \
    --endpoint-public-key 'PUB_****************************************'  \
    --private-key 'PRIV_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB'          \
    --source-peer-ip 192.168.4.3                                          \
    --keep-alive 10

I.e. the only difference is --reverse, and the fact that the second address that you call "destination address" is actually the source-peer-ip of the onetun instance.

Thus any other client (that uses Wireguard or is routed through the Wireguard router) might just connect to 192.168.4.3:8080, which in fact would imply that onetun running locally would receive TCP packets related to inbound connections. So it could just inject these in its TCP/IP stack that would trigger some sort of accept inside onetun that instead would connect to the local server running on the onetun client.

@aramperes
Copy link
Owner

aramperes commented Oct 16, 2021

That would limit the port on the remote server to only be accessible via onetun's peer IP, which IMO reduces the utility compared to SSH's reverse tunnelling, which allows opening a port on any interface.

  • SSH's reverse tunnelling capability:
    [any interface]:[any port] <- [ssh] <- [sshd] <- [any interface]:[any port] <- client TCP connect
    
  • Suggested onetun reverse tunnelling capability:
    [any interface]:[any port] <- [onetun] <- [wireguard] <- [onetun peer IP]:[any port] <- client TCP connect
    

I can see how that would still be useful in some cases though, where you want to make a local port accessible to your WireGuard mesh without having to install WG/root access. I'll look into it for v0.3.

@aramperes aramperes added this to the v0.3 milestone Oct 16, 2021
@cipriancraciun
Copy link
Author

[any interface]:[any port] <- [onetun] <- [wireguard] <- [onetun peer IP]:[any port] <- client TCP connect

I agree that the above is even better that what I've proposed.


My intended use-case is the following: Imagine I have an "HTTP router" (for example HAProxy) installed somewhere on a internet-accessible node. With that "HTTP router" I can route HTTP requests (based on Host or path) to one of the endpoints that are acessible through Wirefuard, and served at the other end by a server (forwarded via onetun). This would allow local instances running on my development laptop to be reachable from the internet via the "HTTP router". Obviously this is even possible today by using a proper Wireguard client or ssh -R, but I think by using onetun it's even more tidy and nice.

@ViRb3
Copy link

ViRb3 commented Jun 29, 2022

Is remote port forwarding actually implemented in 73671a4, or is it just the parsing part? I'm asking because I have a use case that I can't seem to get working. I'm experimenting with a VPN provider that allows you to forward ports from the VPN public IP to your internal IP via the tunnel. This way, you can expose services without revealing your personal IP. So, it looks something like:

client --TCP--> VPN endpoint --WG tunnel--> me

I tried the following onetun command:

onetun --endpoint-addr XXX --endpoint-public-key XXX --private-key XXX --source-peer-ip XXX -keep-alive 10 -r 12345:localhost:12345:TCP,UDP

The idea is then, I should be able to reach my service on port 12345 by calling the VPN endpoint's port 12345. But it does not work... If I connect to the VPN using the official WireGuard desktop client, then the same scenario works.

Thanks!

@aramperes
Copy link
Owner

@ViRb3 It's only the parsing for now, I merged that in in case someone has time to implement this feature. Otherwise I'll start implementing it over time.

@ViRb3
Copy link

ViRb3 commented Jun 29, 2022

Ah, makes sense. I don't have the time or knowledge myself, but looking forward to this feature getting implemented by any other means.

@aramperes
Copy link
Owner

No problem! It'll be a very useful feature to have for sure. It's not going to be super difficult to adapt the existing code, my main blocker is abstracting the smoltcp core enough so that it can support both directions.

@jonmcox
Copy link

jonmcox commented Jan 28, 2023

I think having the option to support [--reverse] would be very nice. This would open up numerous options for connecting to client resources. Any thoughts on when (or if) this feature will be supported? In either case this is a very nice project!

@whmountains
Copy link

I would be interested in sponsoring this feature and/or placing a bounty if the option were available.

@vi
Copy link

vi commented Aug 13, 2023

Note: my new project wgslirpy may be of interest of you want onetun, but in reverse.

It forwards all the connections, not one by one.

@colemickens
Copy link

onetun looks like exactly what I need -- I want to terminate TLS and accept HTTP on a remote server, reverse proxy to a onetun peer that is forwarding traffic to caddy, running on localhost, configured to route to various local services on various ports based on the Host header.

I can't quite wrap my head around wgslirpy and don't really want it to mess with DNS, nor forward all traffic.

I don't want to be annoying, but I would definitely donate to this cause or someone taking it on. I don't think smoltcp is something I can just dive into with my knowledge, nor is something I can dig into right now.

It seems like onetun with reverse connections, combined with caddy on other sides, is basically cloudflare tunnel but freer, and better.

@vi
Copy link

vi commented Feb 20, 2024

@colemickens , If you have proper access both to the remote server and to local host then maybe better just configure proper, in-kernel Wireguard connection (with a port redirection rule) instead of using user-space hacks?

@colemickens
Copy link

@vi Indeed that's the approach I'm trialing now. However, this is part of a dev environment that otherwise is very, very portable, non-root, etc. My colleagues will probably rather tolerate "use root" over "use cloudflare" but the real ideal would be to just have this packaged as another script we run with process-compose.

@vi
Copy link

vi commented Feb 20, 2024

@colemickens For easy, but temporary dev setup you may want to use ngrok or something like that, if you want to just accept global https:// on local machine.

@Nsttt
Copy link

Nsttt commented Mar 4, 2024

Very interested on this working btw. I don't have as much Rust knowledge but I'd like to give it ago. Any advice or place in the code where I should start looking ? @aramperes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants