coder / code-server

VS Code in the browser
https://coder.com
MIT License
68.72k stars 5.64k forks source link

Forward non-http ports and non-localhost ips #5723

Open sibidharan opened 2 years ago

sibidharan commented 2 years ago

Is there an existing issue for this?

OS/Web Information

Steps to Reproduce

  1. Spawn a service in a neighbour container
  2. Under ports, paste container-ip:host
  3. It tells remotehost:port is forwarded, but it is unable to do

When I open the forwarded URL proxy, it says

connect ECONNREFUSED 0.0.0.0:8080

Expected

The service running at remotehost:port should be forwarded via web proxy

Actual

Only locally running ports are being forwarded and remorehost:port is not being forwarded unlike VS Code Desktop. It is not even respecting the host part and just attempting to forward a locally running port.

Logs

No response

Screenshot/Video

No response

Does this issue happen in VS Code or GitHub Codespaces?

Are you accessing code-server over HTTPS?

Notes

No response

jsjoeio commented 2 years ago

Can you elaborate "Spawn a service in a neighbour container"? Then I can try and reproduce this locally.

aureliainnovatives commented 2 years ago

I am facing relatively same problem. If I run a Node App on port 3000 via Code-Server container and NGinx Proxy module, it's not accessible via url/proxy/3000 port. How to get rid of proxy/ and allow it like URL:3000 ?

jsjoeio commented 2 years ago

Hmm 🤔 @code-asher any ideas on how this should work behind nginx?

sibidharan commented 2 years ago

Can you elaborate "Spawn a service in a neighbour container"? Then I can try and reproduce this locally.

Sorry for late response @jsjoeio

Hi,

For example, in a docker compose, I spawn 3 containers, one is MySQL, another one is Adminer and another one is my Apache+PHP+Codeserver containers. When these 3 containers are spawned, they are reachable within themselves. If I forward container-ip:3306 in my desktop vs code over SSH, it forwards container-ip:3306 over SSH to my localhost:3306.

If my codeserver can see any host:IP, it should be able to forward it. For now, it is just looking in localhost and not for the hosts/servers running on the same/reachable network, even if I specify host/ip. But this works correctly in my Desktop VS Code.

In the below example, a MongoDB service is running on that IP:port and my desktop VS code is able to port forward that.

Screenshot 2022-11-01 at 5 28 17 AM

If not MongoDB, at least the code-server should be able to forward HTTP, like adminer.

jsjoeio commented 2 years ago

Thanks for elaborating! I'm not sure how'd we implement this on the code-server side 🤔

@code-asher any ideas?

code-asher commented 2 years ago

I believe we have the proxy hardcoded to localhost right now so we will need to fix that.

code-asher commented 2 years ago

Uh I might have misread the question. For implementing maybe we can leave the IP alone if it is 172.*?

code-asher commented 2 years ago

Actually we should just always leave the IP alone I think and when it is missing then we default to localhost.

code-asher commented 2 years ago

But that means we need to encode the IP into the proxy URL somehow. /proxy/3000?ip=[ip] or /proxy/[ip]/3000 for example.

sibidharan commented 2 years ago

Uh I might have misread the question. For implementing maybe we can leave the IP alone if it is 172.*?

I don't think so.. If the IP is reachable, code-server should forward it. I don't know how protocols like MySQL or MongoDB work in HTTPS.. There should be some way!

benz0li commented 2 years ago

But that means we need to encode the IP into the proxy URL somehow. /proxy/3000?ip=[ip] or /proxy/[ip]/3000 for example.

@code-asher Does this affect https://github.com/coder/code-server/blob/main/patches/proxy-uri.diff?

code-asher commented 2 years ago

Ah yeah good point, I think we would need to add something like {{ip}} to VSCODE_PROXY_URI? But to prevent breakage maybe we can default to localhost when the endpoint is /proxy/{{ip}}/3000 or whatever format we settle on.

benz0li commented 2 years ago

Ah yeah good point, I think we would need to add something like {{ip}} to VSCODE_PROXY_URI?

Only if format /proxy/{{ip}}/{{port}}/[path/to/page] is settled on.

But to prevent breakage maybe we can default to localhost when the endpoint is /proxy/{{ip}}/3000 or whatever format we settle on.

If format /proxy/{{port}}/[path/to/page]?ip=192.0.2.2^1 is settled on and query string parameter ip is unset I expect to default to localhost.

benz0li commented 2 years ago

@code-asher @jsjoeio Please make sure that proxying is restricted to the following ranges:

IPv4

plus 127.0.0.1^2/localhost.

IPv6

plus ::1^4/localhost.

Proxying to arbitrary IPs must be prevented.
👉 Otherwise, this opens up an incredible number of (undesirable) use cases.

benz0li commented 2 years ago

I prefer format /proxy/{{port}}/[path/to/page]?ip=192.0.2.2.

code-asher commented 2 years ago

Great points and thank you for the links!!

I prefer the query parameter as well but I am concerned that the application itself might use query parameters and have one called ip or maybe it is an app with multiple pages and navigating to a page drops the ip query parameter.

If we embed it into the path on the other hand the application would not be able to mess it up.

We could make it a requirement that applications running behind code-server's proxy specially treat the ip query variable if it exists but I could see that not going too well. XD

benz0li commented 2 years ago

I prefer the query parameter as well but I am concerned that the application itself might use query parameters and have one called ip or maybe it is an app with multiple pages and navigating to a page drops the ip query parameter.

Understood.

If we embed it into the path on the other hand the application would not be able to mess it up.

True.

We could make it a requirement that applications running behind code-server's proxy specially treat the ip query variable if it exists but I could see that not going too well. XD

Agreed.

benz0li commented 2 years ago

@code-asher I do not like to modify the VSCODE_PROXY_URI (again). Applications and/or extension making use of VSCODE_PROXY_URI are running on 127.0.0.1/localhost by definition.

It should be possible to differentiate between /proxy/{{port}}/[path/to/page] and /proxy/{{ip}}/{{port}}/[path/to/page] and proxy the former to 127.0.0.1/localhost and the latter to ip.
ℹ️ For IPv4: If the part after the second / does not contain a ., it is already the port – no ip set; thus forward to 127.0.0.1/localhost.

sibidharan commented 2 years ago

@code-asher @jsjoeio @benz0li

How we put the IP into the path is one thing, but I am not sure how protocols like MySQL, MongoDB can be forwarded. It will be very difficult indeed because of the encryption. Many protocols and simple TCP/UDP don't need SSL.

For example, in my setup, the code-server is running on port 1111 and we have a reverse proxy that opens the code-server via SSL over a domain name. To make a lot of features work, like Clipboard, we need SSL. But we don't need SSL for many other protocols. So when I forward a port, instead of proxying it over a URL, is it possible to open a port in the same server and forward it?

Since my code-server is running on 172.20.0.5:1111, if I forward a service running on 172.20.0.6:3306, make the port available on 172.20.0.5:3306 if the port 3306 is available on the server and change the port to some random port if the port is not available (Just like Desktop VS Code). This way, more protocols can be forwarded than just HTTP(S). And this doesn't affect code-server in any way, and the forward remains open as long as the code-server session is open.

In my case of using a reverse-proxy to access code-server over domain name, it will be meaningful to make the proxy forward it over IP instead of a domain name (because reverse-proxy doesn't forward all ports, and it works with domain name). I guess instead of displaying domain name in Local Address column, use the IP of any chosen interface, and this can be set over the command line like --forwarder-iface=eth0 and so code-server knows where to forward, and display the IP in Local Address column effortlessly.

I am facing relatively same problem. If I run a Node App on port 3000 via Code-Server container and NGinx Proxy module, it's not accessible via url/proxy/3000 port. How to get rid of proxy/ and allow it like URL:3000 ?

And I believe this is what this comment is trying to tell.

sibidharan commented 2 years ago

Proxying to arbitrary IPs must be prevented. 👉 Otherwise, this opens up an incredible number of (undesirable) use cases.

IPv4

  • 10.0.0.0/81
  • 172.16.0.0/121
  • 192.168.0.0/161

plus 127.0.0.12/localhost.

IPv6

  • fc00::/73

plus ::14/localhost.

We cannot limit only to this range - lemme tell you why.

In the below image, I have forwarded icanhazip.com:80 (which just displays the end user IP address) and it is forwarded to localhost:52955

Screenshot 2022-11-08 at 8 44 37 PM

My current public IP is 49.206.9.41 and if I open https://icanhazip.com, it says the same.

Since this https://icanhazip.com (also works on http) is hosted behind Cloudflare proxy, my VS Code Desktop resolve the host:port to IP:port and trying to forward the IP only and so it says the following error.

Screenshot 2022-11-08 at 8 50 40 PM

This is because the Cloudflare IP has many servers running behind it and only reachable with a proper domain name. Forward won't work behind proxies that need domain name mandatorily. If I setup a proper forward proxy, I am able to forward this (no time for this now, so I am setting up my own server without any reverse-proxy)

...

I have hosted my own server that tells my IP and hosted it in http://whatismyip.selfmade.ninja and it doesn't work behind any proxy.

When I open it directly:

Screenshot 2022-11-08 at 9 02 44 PM

Look below, I have forwarded it from a server that I have access over wireguard:

Screenshot 2022-11-08 at 8 58 14 PM

When I open the forwarded one:

Screenshot 2022-11-08 at 9 03 35 PM

It says the server's public IP (95.111.198.224) of my 172.0.0.5 (that's on wireguard), because VS Code Desktop is able to forward any arbitrary IP - and this is like I am opening http://whatismyip.selfmade.ninja from 95.111.198.224

This opens up a lot of opportunities for developers, and I don't understand what undesirable things will happen by forwarding arbitrary IPs. Why not code-server do the same?

benz0li commented 2 years ago

It says the server's public IP (95.111.198.224) of my 172.0.0.5 (that's on wireguard), because VS Code Desktop is able to forward any arbitrary IP) - and this is like I am opening http://whatismyip.selfmade.ninja from 95.111.198.224

Since VS Code Desktop [and the computer it runs on] is under your control, that is fine.

This opens up a lot of opportunities for developers, and I don't understand what undesirable things will happen by forwarding arbitrary IPs.

Because if code-server is deployed as SaaS, users would be able to use your server as a proxy for pretty much anything.
ℹ️ For this reason this functionality should be restricted to private subnets.

sibidharan commented 2 years ago

Because if code-server is deployed as SaaS, users would be able to use your server as a proxy for pretty much anything. ℹ️ For this reason this functionality should be restricted to private subnets.

This is a potential security risk, agreed.

But a user can do this whatsoever if he has a shell, by doing an SSH port forward. So why don't we let the admins decide if the code-server can allow forward on all IP ranges or only private IP with a configuration like allowed-ips as an array that takes CIDR - and it can default to Class A,B&C, so unless modified, it won't allow forwarding.?

code-asher commented 2 years ago

I like the idea of a whitelist that you can extend or override through the config.yaml or command-line flags although it does seem pretty easy to bypass. You could spin up or write your own proxy, access it through code-server's proxy, then access whatever you want anyway.

@benz0li I like how you think. So we will leave VSCODE_PROXY_URI alone. If for some reason applications/extensions do start needing to specify a non-localhost IP we can revisit. The algorithm you laid out for differentiating looks great to me as well.

@sibidharan Ahh I skipped over the part about non-HTTP protocols, thanks for pointing that out! Your solution makes sense to me.

Toskies commented 1 year ago

The service I deployed is in Kubernetes' pod, and the localaddress provided by the codeserver auto forward port is https:///notebook/northstar-team/test-isaacsim/proxy/8211/ When I use this link to access, I reported an error not found. My normal link to access the service is http:// ip :8211/streaming/client I tried https:///notebook/northstar-team/test-isaacsim/proxy/8211/streaming/client , But it's not the interface I want codeserver

code-asher commented 1 year ago

@Toskies Do you have the same problem if you use /absproxy/8211/ instead?

You might need to log the requests in your app to see if it is getting what it expects. Unless the 404 comes from code-server and not your app?

sibidharan commented 1 year ago

You could spin up or write your own proxy, access it through code-server's proxy, then access whatever you want anyway.

Yes, I am able to do this using socat and its forwarding anything I want. For example,

socat TCP-LISTEN:8081,reuseaddr,fork TCP:adminer.selfmade.ninja:8080

this command could forward adminer.selfmade.ninja:8080 to my localhost's 8081 and I am able to view it via my --proxy-domain like https://8081.proxy.domain

I have setup a container with dynamic proxy, and its working like a charm. So adding this as a feature is much appreciated with whitelist feature.

image

And the feature doesn't do what the placeholder says! Please fix it, let us forward remote host ports also.