SSH/DevContainer Port Forwarding broken
max06 opened this issue · 17 comments
Does this issue occur when all extensions are disabled?: Yes/No
Version: 1.82.0-insider (system setup)
Commit: 3cd6f481266dcbd2ca2fcff43b4465d747c78e2f
Date: 2023-08-31T17:34:55.916Z
Electron: 25.7.0
ElectronBuildId: 23434598
Chromium: 114.0.5735.289
Node.js: 18.15.0
V8: 11.4.183.29-electron.0
OS: Windows_NT x64 10.0.22621
Issue similar to #190859 - this time it affects Devcontainers running on remote ssh hosts
Client: Windows 11
Remote-Host: Ubuntu 22.04
Container: Debian 11
Repo for reproduction: https://github.com/gecio/gecio.github.io
Steps to Reproduce:
- Connect to ssh host
- Clone Repo
- Open in devcontainer when asked
- Launch Task "Serve" to start webserver
- Open http://localhost:4000 and see indefinite loading.
I can't test it without the remote ssh host :/
Shared-Log
2023-09-01 00:51:07.658 [info] [SharedProcessTunnelService] Created tunnel 1: 127.0.0.1:64076 (local) to 127.0.0.1:7863 (remote).
2023-09-01 00:51:07.673 [info] [SharedProcessTunnelService] Created tunnel 2: 127.0.0.1:33761 (local) to 127.0.0.1:33761 (remote).
2023-09-01 00:51:07.833 [info] [SharedProcessTunnelService] Created tunnel 3: localhost:4000 (local) to localhost:4000 (remote).
2023-09-01 00:51:07.834 [info] [SharedProcessTunnelService] Created tunnel 4: localhost:35729 (local) to localhost:35729 (remote).
2023-09-01 00:51:09.216 [info] Getting Manifest... ms-vscode-remote.remote-containers
2023-09-01 00:51:09.313 [info] Installing extension: ms-vscode-remote.remote-containers
2023-09-01 00:51:10.103 [info] Extension signature is verified: ms-vscode-remote.remote-containers
2023-09-01 00:51:10.426 [info] Extracted extension to file:///c%3A/Users/max06/.vscode-insiders/extensions/ms-vscode-remote.remote-containers-0.308.0: ms-vscode-remote.remote-containers
2023-09-01 00:51:10.432 [info] Renamed to c:\Users\max06\.vscode-insiders\extensions\ms-vscode-remote.remote-containers-0.308.0
2023-09-01 00:51:10.439 [info] Extracting extension completed. ms-vscode-remote.remote-containers
2023-09-01 00:51:10.463 [info] Extension installed successfully: ms-vscode-remote.remote-containers
2023-09-01 00:51:10.469 [info] Marked extension as uninstalled ms-vscode-remote.remote-containers-0.307.0
2023-09-01 00:51:12.628 [info] [SharedProcessTunnelService] Created tunnel 5: 127.0.0.1:42025 (local) to 127.0.0.1:42025 (remote).
2023-09-01 00:51:30.294 [info] Creating a socket (renderer-Tunnel-f2cc70c7-d306-4708-b542-3bfdd2cb513f)...
2023-09-01 00:51:30.416 [info] Creating a socket (renderer-Tunnel-f2cc70c7-d306-4708-b542-3bfdd2cb513f) was successful after 123 ms.
2023-09-01 00:51:30.957 [info] Creating a socket (renderer-Tunnel-57cbefc6-cb29-42ef-89ac-2ff5873ad23a)...
2023-09-01 00:51:31.049 [info] Creating a socket (renderer-Tunnel-57cbefc6-cb29-42ef-89ac-2ff5873ad23a) was successful after 93 ms.
2023-09-01 00:51:31.223 [info] Creating a socket (renderer-Tunnel-d3fcfdea-adbf-44f9-a6da-2d1089f1c7fd)...
2023-09-01 00:51:31.311 [info] Creating a socket (renderer-Tunnel-d3fcfdea-adbf-44f9-a6da-2d1089f1c7fd) was successful after 90 ms.
2023-09-01 00:56:31.298 [info] Creating a socket (renderer-Tunnel-ec10ac1a-bbec-46d3-bb84-2667f176bf2f)...
2023-09-01 00:56:31.400 [info] Creating a socket (renderer-Tunnel-ec10ac1a-bbec-46d3-bb84-2667f176bf2f) was successful after 101 ms.
2023-09-01 00:58:16.519 [info] Creating a socket (renderer-Tunnel-bebfb153-c346-414c-bdcf-e567fb8e8bf6)...
2023-09-01 00:58:16.623 [info] Creating a socket (renderer-Tunnel-bebfb153-c346-414c-bdcf-e567fb8e8bf6) was successful after 104 ms.
2023-09-01 00:58:16.783 [info] Creating a socket (renderer-Tunnel-54b3ca0c-f89e-4827-bd48-d42869c6094f)...
2023-09-01 00:58:16.891 [info] Creating a socket (renderer-Tunnel-54b3ca0c-f89e-4827-bd48-d42869c6094f) was successful after 109 ms.
Dev console doesn't contain anything related.
The extension host shows:
2023-09-01 00:53:21.861 [error] Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
2023-09-01 00:53:21.861 [error] Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
2023-09-01 00:53:21.985 [error] Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
2023-09-01 00:53:22.031 [error] Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
2023-09-01 00:53:22.451 [error] Error: read ECONNRESET
at TCP.onStreamRead (node:internal/stream_base_commons:217:20)
Although I'm not sure if that's related.
The server output is interesting:
2023-08-31 23:03:58.609 [error] Error: connect ECONNREFUSED ::1:4000
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16)
2023-08-31 23:03:58.870 [error] Error: connect ECONNREFUSED ::1:4000
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1494:16)
This is directly related - it happens right/shortly after opening the url in the browser.
Insiders has upgraded to Node 18 which now prefers ipv6 in dns lookups for localhost. I wonder if your service listens only on ipv4 localhost. When connecting to a tunnel we ask for localhost
, though this might be configurable (@alexr00?)
On the server we could do what I did in microsoft/dev-tunnels#292 and try to connect both to ipv4 and ipv6 localhost for any forwarded connection asking for localhost
, and use whatever is accepted first.
Using 127.0.0.1 has no effect...
Worth mentioning: My remote host and the docker network are both ipv6 enabled (dual stack)
I corrected my comment, that would not have worked.
Do you know if the server running in the repo bound to the ipv6 or ipv4 localhost?
$ ss -tulpn | grep 4000
tcp LISTEN 0 4096 127.0.0.1:4000 0.0.0.0:* users:(("bundle",pid=48387,fd=11))
Ah, okay. That seems to be what is happening. I imagine this may be a popular issue with our next release. Will discuss whether we want to put in a patch at this point.
If you pull the regular release to node 18 - that would be great. I only work in devcontainers... 😅
If not... I can move those containers that use port forwarding back to the regular version.
Local/dev verification steps:
- Have two machines on an ipv6-enabled network, and 'remote' and 'local'
- Modify
extensions/vscode-test-resolver/src/extension.ts
to return{ connectionToken: 'test', host: '<ip or host>', port: 9888 }
from theresolve
method on the test resolver, and comment out itstunnelFactory
- Run
./scripts/code-server.sh --host=0.0.0.0 --connectionToken=test
on the 'remote' machine - On the 'local' machine, run OSS dev and run the command "Connect to TestResolver in Current Window"
- Forward port 3000 on the local machine
- On the remote machine, run
npx serve -l "tcp://[::1]:3000"
. Verify you can hit it on the local machine. This should work in main. - On the remote machine, run
npx serve -l tcp://127.0.0.1:3000
. Verify you can hit it on the local machine. This will fail 🐛
Labelling as candidate for discussion
7. On the remote machine, run
npx serve -l tcp://127.0.0.1:3000
. Verify you can hit it on the local machine. This will fail 🐛
@deepak1556 This sounds like the extension host uses ipv6 to connect to localhost. Wasn't --dns-result-order=ipv4first
supposed to keep the Node 16 behavior of preferring ipv4?
Yes the extension host prefers the legacy result order of ipv4 first, it is configured for both local and remote extension hosts
I am not familiar with port forwarding code, but the change here #191950 is addressing the connection to the server. I have not changed the behavior for server main process, basically it will use the newer behavior of whatever the OS prefers.
Should the server also be changed to use the legacy result order ?
Not entirely sure, but it seems like it would make sense to keep the user-visible behavior the same and avoid surfacing the change in Node.js.
On the other hand, users will gradually upgrade to Node.js 18 and since server.listen
also changes its behavior, the ports the forwarding code is connecting to will change interfaces. So maybe the autoSelectFamily
flag you suggest or @connor4312's probing of both interfaces when connecting to localhost might be more future proof.
The code that sets up a tunnel executes in the server process, where it tries to connect
to localhost
, so that is why the extension host flag doesn't have any effect. I also like the idea of using node's builtin autoSelectFamily
rather than us reimplementing it.
The repro steps which worked for me:
- install ubuntu 22.04.3 in Parallels
- change
/etc/hosts
and addlocalhost
to::1
e.g.
127.0.0.1 localhost
127.0.1.1 ubuntu2204
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
- connect via SSH
- create a js file
npm install yaserver
const yaserver = require('yaserver');
const http = require('http');
const PORT = 3002;
yaserver.createServer({
rootDir: __dirname
}).then((staticServer) => {
const server = http.createServer((request, response) => {
return staticServer.handle(request, response);
});
server.listen(PORT, '127.0.0.1', () => {
// server.listen(PORT, '::1', () => {
});
});
- launch the file via the node installed by the server e.g.
/home/alex/.vscode-server-insiders/cli/servers/Insiders-dd112ec0243c4b42bb3106e64df1688e242a6559/server/node server.js
- add port forwarding for port 3002
- open localhost:3002 in the local machine
I just want to raise the question if makes sense to build something complicated for detecting the address family now - not sure how often ipv6 is used for localhost binding?
I'd be perfectly fine if it always goes for ipv4 for the time being.
Edit: ... or I take the fix that just got finished while writing this comment 😂
Verified in latest insider, works.
Commit: f1302be1e67e3af5fbeb8bbb2ea784de7bc96150
Date: 2023-09-01T11:08:40.414Z
Thank you very much for saving me!
For documentation:
2023-09-01 12:31:17.112 [error] AggregateError
at internalConnectMultiple (node:net:1081:18)
at afterConnectMultiple (node:net:1532:5)
does now show up in the server output when opening the port. Doesn't seem to prevent it from working though.