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

TCP reset on remote connection failure #538

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

liojacqs
Copy link

@liojacqs liojacqs commented Nov 3, 2024

There is currently no possibility for a "simple" TCP client (i.e sending data and not expecting any particular feedback), to know that a remote end is not actually responding, because:

  • On the output side, SSH tunnel is accepted before dialing remote TCP connection, so for the input side, as soon as there is a SSH tunnel then it is OK
  • Consequently on the input side, no check can be made to ensure remote connection is ok before forwarding input data

This is problematic when dealing with some remote write only devices that may or may not be up and running, as chisel is "hiding" the non availability of the devices.
As the chisel listening port will always be up, it is indeed impossible to have the same behaviour as when dealing directly with the device, but it is possible at some point to abruptly reset the TCP connection, so the client has a chance to catch an error.

This proposal implements the following changes for TCP connection:

  • Remote tcp dial before accepting SSH tunnel
  • SSH error in case of remote dial issue, with the origin of the error logged on the input proxy side
  • SSH connection check before "pipe"
  • TCP connection reset in case of SSH connection error (or now remote tcp dial errors)

Note: Resetting TCP connection requires attempting to write some data to the client, so the origin of error is used as data as well

With this change, a simple netcat to a Chisel input proxy towards a non reachable remote will now:

  • Return a non zero error code
  • Show the connection error reason

Example below.

Server log

$ bin/chisel server --reverse -v
2024/11/03 23:16:12 server: Reverse tunnelling enabled
2024/11/03 23:16:12 server: Listening on http://0.0.0.0:8080
2024/11/03 23:16:16 server: session#1: Handshaking with [::1]:58876...
2024/11/03 23:16:16 server: session#1: Verifying configuration
2024/11/03 23:16:16 server: session#1: tun: Created
2024/11/03 23:16:16 server: session#1: tun: SSH connected
2024/11/03 23:16:16 server: session#1: tun: proxy#R:9100=>localhost:9101: Listening
2024/11/03 23:16:16 server: session#1: tun: Bound proxies
2024/11/03 23:16:25 server: session#1: tun: proxy#R:9100=>localhost:9101: conn#1: Open
2024/11/03 23:16:25 server: session#1: tun: proxy#R:9100=>localhost:9101: conn#1: Stream error: ssh: rejected: connect failed (Failed to connect to localhost:9101: dial tcp [::1]:9101: connect: connection refused)
2024/11/03 23:16:25 server: session#1: tun: proxy#R:9100=>localhost:9101: conn#1: Reset

Client logs

$ ./bin/chisel client -v localhost:8080 R:0.0.0.0:9100:localhost:9101/tcp
2024/11/03 23:16:16 client: Connecting to ws://localhost:8080
2024/11/03 23:16:16 client: Handshaking...
2024/11/03 23:16:16 client: Sending config
2024/11/03 23:16:16 client: Connected (Latency 3.2935ms)
2024/11/03 23:16:16 client: tun: SSH connected
2024/11/03 23:16:25 client: tun: Failed to connect to localhost:9101: dial tcp [::1]:9101: connect: connection refused

netcat

$ nc -v localhost 9100 < /etc/hosts ; echo $?
Connection to localhost port 9100 [tcp/hp-pdl-datastr] succeeded!
ssh: rejected: connect failed (Failed to connect to localhost:9101: dial tcp [::1]:9101: connect: connection refused)
141

Will prevent the input proxy to send anything on SSH if it's not possible to connect to the remote end.
If the TCP connection fails, SSH connection attempt is rejected with reason ConnectionFailed, and and the TCP connection error message.
On remote connection failure, reset TCP connection, so the client (if well written), may be aware of an issue, even if all the data could be sent before (with TCP, data can be sent before Accept() on the server side).
The reason for failure is sent back to the client.
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 this pull request may close these issues.

1 participant